local ____lualib = require("lualib_bundle") local __TS__Class = ____lualib.__TS__Class local Map = ____lualib.Map local __TS__New = ____lualib.__TS__New local __TS__StringStartsWith = ____lualib.__TS__StringStartsWith local __TS__StringSubstring = ____lualib.__TS__StringSubstring local __TS__ArrayIndexOf = ____lualib.__TS__ArrayIndexOf local __TS__ArraySplice = ____lualib.__TS__ArraySplice local __TS__ObjectEntries = ____lualib.__TS__ObjectEntries local __TS__Delete = ____lualib.__TS__Delete local __TS__StringIncludes = ____lualib.__TS__StringIncludes local __TS__NumberToFixed = ____lualib.__TS__NumberToFixed local ____exports = {} local ____modifier_general_arc = require("abilities.modifiers.modifier_general_arc") local modifier_general_arc = ____modifier_general_arc.modifier_general_arc local ____modifier_kitty_flex_catakeet = require("abilities.modifiers.modifier_kitty_flex_catakeet") local KITTY_FLEX_CATAKEET_MODEL = ____modifier_kitty_flex_catakeet.KITTY_FLEX_CATAKEET_MODEL local modifier_kitty_flex_catakeet = ____modifier_kitty_flex_catakeet.modifier_kitty_flex_catakeet local DEFAULT_SOUND_CONFIG = {cooldown = 15, globalCooldown = 0, blocksOtherSounds = false, blockDuration = 0} local SOUND_CONFIGS = { i_am_sad = { cooldown = 300, globalCooldown = 300, blocksOtherSounds = true, blockDuration = 5.7, effect = "rain", effectDuration = 5.7, timescale = 0.1 }, jump = { cooldown = 300, globalCooldown = 300, blocksOtherSounds = true, blockDuration = 38, effect = "jump", effectDuration = 38, jumpInterval = 0.35, jumpRadius = 350, jumpHeight = 250, jumpHeightOnPlace = 250 }, agent_gabena = DEFAULT_SOUND_CONFIG, byd_dobr_idi = DEFAULT_SOUND_CONFIG, cat_shnapy = DEFAULT_SOUND_CONFIG, dobro_pozhalovat_v_club = DEFAULT_SOUND_CONFIG, eto_prosto_okhueno = DEFAULT_SOUND_CONFIG, get_out = DEFAULT_SOUND_CONFIG, ia_vas_unichtozhu = DEFAULT_SOUND_CONFIG, kak_rulit = DEFAULT_SOUND_CONFIG, kto_myaukaet = DEFAULT_SOUND_CONFIG, Muhehehehe = DEFAULT_SOUND_CONFIG, ne_tvoy_uroven_dorogoy = DEFAULT_SOUND_CONFIG, ne_ponimaiu_karina_strimersha_slozhno_slozhno = DEFAULT_SOUND_CONFIG, nikhuia_ne_ponial_no_ochen_interesno = DEFAULT_SOUND_CONFIG, oi_tak_nravitsa = DEFAULT_SOUND_CONFIG, olyhi_bezdari_ogyzki = DEFAULT_SOUND_CONFIG, ou_mai = DEFAULT_SOUND_CONFIG, po_syobam = DEFAULT_SOUND_CONFIG, poshel_process = DEFAULT_SOUND_CONFIG, posledniy_ponedelnik_zivesh = DEFAULT_SOUND_CONFIG, rot_etogo_kazino = DEFAULT_SOUND_CONFIG, s_kakoy_stati = DEFAULT_SOUND_CONFIG, sir_no_sir = DEFAULT_SOUND_CONFIG, sir_yes_sir = DEFAULT_SOUND_CONFIG, stop_mne_ne_priyatno = DEFAULT_SOUND_CONFIG, stoyat_ya_yzhe_eto_sosal = DEFAULT_SOUND_CONFIG, ura_pobeda = DEFAULT_SOUND_CONFIG, uvorot_ot_spelov = DEFAULT_SOUND_CONFIG, v_komp_igri_igral = DEFAULT_SOUND_CONFIG, vot_eto_nikhuia_sebe = DEFAULT_SOUND_CONFIG, zachem_ya_suda_prishel = DEFAULT_SOUND_CONFIG, zaika = DEFAULT_SOUND_CONFIG, kitty_flex = { cooldown = 15, globalCooldown = 0, blocksOtherSounds = true, blockDuration = 13.6, effect = "kitty_flex", effectDuration = 13.6, initialThrowCount = 5, incrementThrowCount = 1, throwRadiusMin = 120, throwRadiusMax = 420, throwHeightMin = 160, throwHeightMax = 340, throwDuration = 0.45, throwInterval = 1, bounceRadiusMin = 80, bounceRadiusMax = 360, bounceHeightMin = 110, bounceHeightMax = 220, bounceIntervalMin = 0.55, bounceIntervalMax = 1, lookIntervalMin = 0.35, lookIntervalMax = 0.75, shakeInterval = 0.35 }, eblo_razraba = DEFAULT_SOUND_CONFIG, kuda = DEFAULT_SOUND_CONFIG, bruh = DEFAULT_SOUND_CONFIG, shizofreniya = DEFAULT_SOUND_CONFIG, vot_eto_povorot = DEFAULT_SOUND_CONFIG, fbi_open_up = DEFAULT_SOUND_CONFIG, nepravilno_poprobuy_esche_raz = DEFAULT_SOUND_CONFIG, dobro_pozhalovat_na_server_shizofreniya = DEFAULT_SOUND_CONFIG, nya = DEFAULT_SOUND_CONFIG, na_nas_napali = DEFAULT_SOUND_CONFIG, murlok = DEFAULT_SOUND_CONFIG, kak_zhit_to_a = DEFAULT_SOUND_CONFIG } ____exports.SoundCooldownSystem = __TS__Class() local SoundCooldownSystem = ____exports.SoundCooldownSystem SoundCooldownSystem.name = "SoundCooldownSystem" SoundCooldownSystem.____file_path = "scripts/vscripts/SoundSystem.lua" function SoundCooldownSystem.prototype.____constructor(self) self.cooldowns = __TS__New(Map) self.cooldownSettings = __TS__New(Map) self.globalCooldowns = __TS__New(Map) self.globalCooldownSettings = __TS__New(Map) self.soundConfigs = __TS__New(Map) self.blockingSounds = __TS__New(Map) end function SoundCooldownSystem.getInstance(self) if not ____exports.SoundCooldownSystem.instance then ____exports.SoundCooldownSystem.instance = __TS__New(____exports.SoundCooldownSystem) end return ____exports.SoundCooldownSystem.instance end function SoundCooldownSystem.prototype.setSoundConfig(self, soundId, config) self.soundConfigs:set(soundId, config) if config.cooldown ~= nil and config.cooldown > 0 then self.cooldownSettings:set(soundId, config.cooldown) print(((("[SoundCooldownSystem] Установлен индивидуальный кулдаун для звука " .. soundId) .. ": ") .. tostring(config.cooldown)) .. " сек") end if config.globalCooldown ~= nil and config.globalCooldown > 0 then self.globalCooldownSettings:set(soundId, config.globalCooldown) print(((("[SoundCooldownSystem] Установлен глобальный кулдаун для звука " .. soundId) .. ": ") .. tostring(config.globalCooldown)) .. " сек") end print((((((("[SoundCooldownSystem] Конфигурация для звука " .. soundId) .. ": cooldown=") .. tostring(config.cooldown or 0)) .. ", globalCooldown=") .. tostring(config.globalCooldown or 0)) .. ", blocksOtherSounds=") .. tostring(config.blocksOtherSounds or false)) end function SoundCooldownSystem.prototype.setCooldown(self, soundId, duration) self.cooldownSettings:set(soundId, duration) print(((("[SoundCooldownSystem] Установлен индивидуальный кулдаун для звука " .. soundId) .. ": ") .. tostring(duration)) .. " сек") end function SoundCooldownSystem.prototype.setGlobalCooldown(self, soundId, duration) self.globalCooldownSettings:set(soundId, duration) print(((("[SoundCooldownSystem] Установлен глобальный кулдаун для звука " .. soundId) .. ": ") .. tostring(duration)) .. " сек") end function SoundCooldownSystem.prototype.getSoundConfig(self, soundId, soundName) return self.soundConfigs:get(self:resolveSoundConfigKey(soundId, soundName)) end function SoundCooldownSystem.prototype.resolveSoundConfigKey(self, soundId, soundName) local function stripStorePrefix(____, value) local prefix = "chat_wheel_sound_" if __TS__StringStartsWith(value, prefix) then return __TS__StringSubstring(value, #prefix) end return value end local candidates = {} if soundId ~= "" then candidates[#candidates + 1] = soundId candidates[#candidates + 1] = stripStorePrefix(nil, soundId) end if soundName ~= nil and soundName ~= "" then candidates[#candidates + 1] = soundName candidates[#candidates + 1] = stripStorePrefix(nil, soundName) end for ____, key in ipairs(candidates) do if self.soundConfigs:has(key) then return key end end return soundName or soundId end function SoundCooldownSystem.prototype.isBlockingOtherSounds(self, soundId) local config = self.soundConfigs:get(soundId) return (config and config.blocksOtherSounds) == true end function SoundCooldownSystem.prototype.getBlockDuration(self, soundId) local config = self.soundConfigs:get(soundId) return config and config.blockDuration or 0 end function SoundCooldownSystem.prototype.setBlocking(self, soundId, isBlocking) if isBlocking then self.blockingSounds:set(soundId, true) else self.blockingSounds:delete(soundId) end end function SoundCooldownSystem.prototype.isAnySoundBlocking(self) return self.blockingSounds.size > 0 end function SoundCooldownSystem.prototype.canPlaySound(self, soundId, playerId) local steamId = PlayerResource:GetSteamAccountID(playerId) if steamId == ____exports.SoundCooldownSystem.NO_COOLDOWN_STEAM_ID then return true end local currentTime = GameRules:GetGameTime() local cooldown = self.cooldownSettings:get(soundId) if cooldown and cooldown > 0 then local playerCooldowns = self.cooldowns:get(soundId) if playerCooldowns then local endTime = playerCooldowns:get(playerId) if endTime and currentTime < endTime then return false end end end local globalCooldown = self.globalCooldownSettings:get(soundId) if globalCooldown and globalCooldown > 0 then local globalEndTime = self.globalCooldowns:get(soundId) if globalEndTime and currentTime < globalEndTime then local playerCooldowns = self.cooldowns:get(soundId) if playerCooldowns and playerCooldowns:has(playerId) then return true else return false end end end return true end function SoundCooldownSystem.prototype.getRemainingCooldown(self, soundId, playerId) local currentTime = GameRules:GetGameTime() local globalRemaining = 0 local individualRemaining = 0 local playerCooldowns = self.cooldowns:get(soundId) if playerCooldowns then local endTime = playerCooldowns:get(playerId) if endTime then individualRemaining = endTime - currentTime if individualRemaining < 0 then individualRemaining = 0 end end end if playerCooldowns and playerCooldowns:has(playerId) then return individualRemaining end local globalCooldown = self.globalCooldownSettings:get(soundId) if globalCooldown and globalCooldown > 0 then local globalEndTime = self.globalCooldowns:get(soundId) if globalEndTime then globalRemaining = globalEndTime - currentTime if globalRemaining < 0 then globalRemaining = 0 end end end return math.max(globalRemaining, individualRemaining) end function SoundCooldownSystem.prototype.setPlayerCooldown(self, soundId, playerId) local currentTime = GameRules:GetGameTime() local globalCooldown = self.globalCooldownSettings:get(soundId) if globalCooldown and globalCooldown > 0 then local globalEndTime = currentTime + globalCooldown self.globalCooldowns:set(soundId, globalEndTime) print(((((("[SoundCooldownSystem] Установлен глобальный кулдаун для звука " .. soundId) .. ": до ") .. tostring(globalEndTime)) .. " (через ") .. tostring(globalCooldown)) .. " сек)") end local cooldown = self.cooldownSettings:get(soundId) if cooldown and cooldown > 0 then if not self.cooldowns:has(soundId) then self.cooldowns:set( soundId, __TS__New(Map) ) end local playerCooldowns = self.cooldowns:get(soundId) local endTime = currentTime + cooldown playerCooldowns:set(playerId, endTime) print(((((((("[SoundCooldownSystem] Установлен индивидуальный кулдаун для игрока " .. tostring(playerId)) .. ", звук ") .. soundId) .. ": до ") .. tostring(endTime)) .. " (через ") .. tostring(cooldown)) .. " сек)") end end function SoundCooldownSystem.prototype.clearCooldown(self, soundId, playerId) local playerCooldowns = self.cooldowns:get(soundId) if playerCooldowns then playerCooldowns:delete(playerId) print((("[SoundCooldownSystem] Кулдаун очищен для игрока " .. tostring(playerId)) .. ", звук ") .. soundId) end end SoundCooldownSystem.NO_COOLDOWN_STEAM_ID = 877002179 ____exports.SoundEventSystem = __TS__Class() local SoundEventSystem = ____exports.SoundEventSystem SoundEventSystem.name = "SoundEventSystem" SoundEventSystem.____file_path = "scripts/vscripts/SoundSystem.lua" function SoundEventSystem.prototype.____constructor(self) self.soundHandlers = __TS__New(Map) self.globalHandlers = {} end function SoundEventSystem.getInstance(self) if not ____exports.SoundEventSystem.instance then ____exports.SoundEventSystem.instance = __TS__New(____exports.SoundEventSystem) end return ____exports.SoundEventSystem.instance end function SoundEventSystem.prototype.onSound(self, soundId, handler) if not self.soundHandlers:has(soundId) then self.soundHandlers:set(soundId, {}) end local ____temp_4 = self.soundHandlers:get(soundId) ____temp_4[#____temp_4 + 1] = handler end function SoundEventSystem.prototype.onAnySound(self, handler) local ____self_globalHandlers_5 = self.globalHandlers ____self_globalHandlers_5[#____self_globalHandlers_5 + 1] = handler end function SoundEventSystem.prototype.triggerSoundEvent(self, playerId, soundId, soundName, soundData) local eventData = {playerId = playerId, soundId = soundId, soundName = soundName, soundData = soundData} for ____, handler in ipairs(self.globalHandlers) do do local function ____catch(e) print("[SoundEventSystem] Ошибка в глобальном обработчике звука: " .. tostring(e)) end local ____try, ____hasReturned = pcall(function() handler(nil, eventData) end) if not ____try then ____catch(____hasReturned) end end end local handlers = self.soundHandlers:get(soundId) if handlers then for ____, handler in ipairs(handlers) do do local function ____catch(e) print((("[SoundEventSystem] Ошибка в обработчике звука " .. soundId) .. ": ") .. tostring(e)) end local ____try, ____hasReturned = pcall(function() handler(nil, eventData) end) if not ____try then ____catch(____hasReturned) end end end end if soundName and soundName ~= soundId then local handlersByName = self.soundHandlers:get(soundName) if handlersByName then for ____, handler in ipairs(handlersByName) do do local function ____catch(e) print((("[SoundEventSystem] Ошибка в обработчике звука " .. soundName) .. ": ") .. tostring(e)) end local ____try, ____hasReturned = pcall(function() handler(nil, eventData) end) if not ____try then ____catch(____hasReturned) end end end end end end function SoundEventSystem.prototype.removeHandler(self, soundId, handler) local handlers = self.soundHandlers:get(soundId) if handlers then local index = __TS__ArrayIndexOf(handlers, handler) if index > -1 then __TS__ArraySplice(handlers, index, 1) end end end function SoundEventSystem.prototype.removeGlobalHandler(self, handler) local index = __TS__ArrayIndexOf(self.globalHandlers, handler) if index > -1 then __TS__ArraySplice(self.globalHandlers, index, 1) end end ____exports.SoundSystemManager = __TS__Class() local SoundSystemManager = ____exports.SoundSystemManager SoundSystemManager.name = "SoundSystemManager" SoundSystemManager.____file_path = "scripts/vscripts/SoundSystem.lua" function SoundSystemManager.prototype.____constructor(self) self.rainStopTimer = nil self.originalTimescale = 1 self.jumpStopTimer = nil self.jumpCycleTimer = nil self.kittyFlexStopTimer = nil self.kittyFlexShakeTimer = nil self.kittyFlexThrowTimer = nil self.kittyFlexUnits = {} end function SoundSystemManager.getInstance(self) if not ____exports.SoundSystemManager.instance then ____exports.SoundSystemManager.instance = __TS__New(____exports.SoundSystemManager) end return ____exports.SoundSystemManager.instance end function SoundSystemManager.prototype.initialize(self) self:setupSoundCooldowns() self:setupSoundWeatherHandler() self:setupJumpSoundHandler() self:setupKittyFlexSoundHandler() end function SoundSystemManager.prototype.setupSoundCooldowns(self) local cooldownSystem = ____exports.SoundCooldownSystem:getInstance() for ____, ____value in ipairs(__TS__ObjectEntries(SOUND_CONFIGS)) do local soundId = ____value[1] local config = ____value[2] cooldownSystem:setSoundConfig(soundId, {cooldown = config.cooldown, globalCooldown = config.globalCooldown, blocksOtherSounds = config.blocksOtherSounds, blockDuration = config.blockDuration}) end end function SoundSystemManager.prototype.updateSoundCooldownInNetTables(self, playerId, soundId, remainingTime) local soundCooldowns = CustomNetTables:GetTableValue( "sound_cooldowns", tostring(playerId) ) if not soundCooldowns then soundCooldowns = {} end soundCooldowns[soundId] = remainingTime CustomNetTables:SetTableValue( "sound_cooldowns", tostring(playerId), soundCooldowns ) end function SoundSystemManager.prototype.startSoundCooldownTimer(self, playerId, soundId) local cooldownSystem = ____exports.SoundCooldownSystem:getInstance() local timerId = (("sound_cooldown_" .. tostring(playerId)) .. "_") .. soundId Timers:RemoveTimer(timerId) Timers:CreateTimer( timerId, { useGameTime = true, endTime = 1, callback = function() local remaining = cooldownSystem:getRemainingCooldown(soundId, playerId) if remaining > 0 then self:updateSoundCooldownInNetTables(playerId, soundId, remaining) return 1 else local soundCooldowns = CustomNetTables:GetTableValue( "sound_cooldowns", tostring(playerId) ) if soundCooldowns then __TS__Delete(soundCooldowns, soundId) CustomNetTables:SetTableValue( "sound_cooldowns", tostring(playerId), soundCooldowns ) end return nil end end } ) end function SoundSystemManager.prototype.setupSoundWeatherHandler(self) local config = SOUND_CONFIGS.i_am_sad local function handleSadSound(____, data) local isIAmSadSound = data.soundName == "i_am_sad" or data.soundId == "i_am_sad" or data.soundId and __TS__StringIncludes(data.soundId, "i_am_sad") or data.soundName and __TS__StringIncludes(data.soundName, "i_am_sad") if not isIAmSadSound then return end print(((("[SoundSystem] Звук " .. data.soundName) .. " воспроизведен игроком ") .. tostring(data.playerId)) .. ", начинаем дождь") if self.rainStopTimer then Timers:RemoveTimer(self.rainStopTimer) self.rainStopTimer = nil end local currentTimescale = Convars:GetFloat("host_timescale") or 1 if currentTimescale >= 0.9 then self.originalTimescale = currentTimescale end Convars:SetFloat("host_timescale", config.timescale) print("[SoundSystem] host_timescale установлен в " .. tostring(config.timescale)) self:startRainForAllPlayers() self.rainStopTimer = Timers:CreateTimer({ useGameTime = false, endTime = config.effectDuration, callback = function() print(("[SoundSystem] Звук " .. data.soundName) .. " закончился, останавливаем дождь и восстанавливаем время") self:stopRainForAllPlayers() Convars:SetFloat("host_timescale", self.originalTimescale) print("[SoundSystem] host_timescale восстановлен в " .. tostring(self.originalTimescale)) self.originalTimescale = 1 self.rainStopTimer = nil return nil end }) end ____exports.SoundEventSystem:getInstance():onSound("i_am_sad", handleSadSound) ____exports.SoundEventSystem:getInstance():onAnySound(handleSadSound) end function SoundSystemManager.prototype.setupJumpSoundHandler(self) local config = SOUND_CONFIGS.jump local function performScreenShake() local SHAKE_START = 0 local SHAKE_STOP = 1 do local playerID = 0 while playerID < DOTA_MAX_PLAYERS do if PlayerResource:IsValidPlayerID(playerID) then local hero = PlayerResource:GetSelectedHeroEntity(playerID) if hero and IsValidEntity(hero) and not hero:IsNull() then local pos = hero:GetAbsOrigin() ScreenShake( pos, 1500, 1600, 0.5, 1700, SHAKE_STOP, true ) ScreenShake( pos, 1500, 1600, 0.5, 1700, SHAKE_START, true ) end end playerID = playerID + 1 end end end local jumpCycleCount = 0 local function performJump() jumpCycleCount = jumpCycleCount + 1 performScreenShake(nil) local JUMP_DURATION = 0.3 local heroes = {} do local i = 0 while i < PlayerResource:GetPlayerCount() do local hero = PlayerResource:GetSelectedHeroEntity(i) if hero and IsValidEntity(hero) and not hero:IsNull() and hero.IsAlive and hero:IsAlive() then heroes[#heroes + 1] = hero end i = i + 1 end end local classnames = {"npc_dota_creature", "npc_dota_base", "npc_dota_creep_neutral"} local allUnits = {} for ____, hero in ipairs(heroes) do allUnits[#allUnits + 1] = hero end for ____, classname in ipairs(classnames) do local units = Entities:FindAllByClassname(classname) for ____, unit in ipairs(units) do if unit and IsValidEntity(unit) and not unit:IsNull() then if unit.IsAlive and unit:IsAlive() then if not (unit.IsRealHero and unit:IsRealHero()) then allUnits[#allUnits + 1] = unit end end end end end print(((((("[SoundSystem] Прыжок #" .. tostring(jumpCycleCount)) .. ", юнитов: ") .. tostring(#allUnits)) .. " (героев: ") .. tostring(#heroes)) .. ")") for ____, unit in ipairs(allUnits) do do if not unit or unit:IsNull() or not IsValidEntity(unit) then goto __continue112 end if unit:HasModifier(modifier_general_arc.name) then goto __continue112 end local unitOrigin = unit:GetAbsOrigin() local targetX local targetY local targetZ local jumpDistance local isHero = unit.IsRealHero and unit:IsRealHero() if isHero then local forwardVector = unit:GetForwardVector() jumpDistance = RandomFloat(config.jumpRadius * 0.5, config.jumpRadius) targetX = unitOrigin.x + forwardVector.x * jumpDistance targetY = unitOrigin.y + forwardVector.y * jumpDistance targetZ = unitOrigin.z else targetX = unitOrigin.x targetY = unitOrigin.y targetZ = unitOrigin.z jumpDistance = 0 end modifier_general_arc:apply(unit, unit, nil, { x = targetX, y = targetY, z = targetZ, duration = JUMP_DURATION, distance = jumpDistance, height = isHero and config.jumpHeight or config.jumpHeightOnPlace, isFlail = false }) if isHero then print((((((("[SoundSystem] Герой " .. unit:GetUnitName()) .. " прыгает в направлении взгляда (") .. __TS__NumberToFixed(targetX, 2)) .. ", ") .. __TS__NumberToFixed(targetY, 2)) .. ") на расстояние ") .. __TS__NumberToFixed(jumpDistance, 2)) else print(("[SoundSystem] Юнит " .. unit:GetUnitName()) .. " прыгает на месте") end end ::__continue112:: end end local function handleJumpSound(____, data) local isJumpSound = data.soundName == "jump" or data.soundId == "jump" or data.soundId and __TS__StringIncludes(data.soundId, "jump") or data.soundName and __TS__StringIncludes(data.soundName, "jump") if not isJumpSound then return end print(((((((("[SoundSystem] Звук " .. data.soundName) .. " (soundId: ") .. data.soundId) .. ") воспроизведен игроком ") .. tostring(data.playerId)) .. ", начинаем цикл прыжков на ") .. tostring(config.effectDuration)) .. " секунд") if self.jumpStopTimer then Timers:RemoveTimer(self.jumpStopTimer) self.jumpStopTimer = nil end if self.jumpCycleTimer then Timers:RemoveTimer(self.jumpCycleTimer) self.jumpCycleTimer = nil end jumpCycleCount = 0 performJump(nil) local function startJumpCycle() self.jumpCycleTimer = Timers:CreateTimer( config.jumpInterval, function() performJump(nil) return config.jumpInterval end ) end startJumpCycle(nil) self.jumpStopTimer = Timers:CreateTimer( config.effectDuration, function() print(("[SoundSystem] Звук " .. data.soundName) .. " закончился, останавливаем прыжки") if self.jumpCycleTimer then Timers:RemoveTimer(self.jumpCycleTimer) self.jumpCycleTimer = nil end self.jumpStopTimer = nil return nil end ) end ____exports.SoundEventSystem:getInstance():onSound("jump", handleJumpSound) ____exports.SoundEventSystem:getInstance():onAnySound(handleJumpSound) end function SoundSystemManager.prototype.setupKittyFlexSoundHandler(self) local config = SOUND_CONFIGS.kitty_flex local KITTY_FLEX_UNIT = "npc_attack_box" local function performScreenShake() local SHAKE_START = 0 local SHAKE_STOP = 1 do local playerID = 0 while playerID < DOTA_MAX_PLAYERS do do if not PlayerResource:IsValidPlayerID(playerID) then goto __continue130 end local hero = PlayerResource:GetSelectedHeroEntity(playerID) if hero and IsValidEntity(hero) and not hero:IsNull() then local pos = hero:GetAbsOrigin() ScreenShake( pos, 2800, 2600, 0.65, 3200, SHAKE_STOP, true ) ScreenShake( pos, 2800, 2600, 0.65, 3200, SHAKE_START, true ) end end ::__continue130:: playerID = playerID + 1 end end end local function stopKittyFlexTimers() if self.kittyFlexShakeTimer then Timers:RemoveTimer(self.kittyFlexShakeTimer) self.kittyFlexShakeTimer = nil end if self.kittyFlexThrowTimer then Timers:RemoveTimer(self.kittyFlexThrowTimer) self.kittyFlexThrowTimer = nil end end local function cleanupKittyFlexCatakeets() for ____, unit in ipairs(self.kittyFlexUnits) do if unit and IsValidEntity(unit) and not unit:IsNull() then unit:RemoveModifierByName(modifier_kitty_flex_catakeet.name) if IsValidEntity(unit) and not unit:IsNull() then UTIL_Remove(unit) end end end self.kittyFlexUnits = {} end local function throwCatakeetsFromHero(____, hero, count) local origin = hero:GetAbsOrigin() do local i = 0 while i < count do do local spawnOffset = RandomVector(RandomFloat(20, 70)) local spawnPos = origin + Vector(spawnOffset.x, spawnOffset.y, 0) spawnPos = GetGroundPosition(spawnPos, hero) local angle = RandomFloat(0, 2 * math.pi) local distance = RandomFloat(config.throwRadiusMin, config.throwRadiusMax) local targetPos = Vector( origin.x + math.cos(angle) * distance, origin.y + math.sin(angle) * distance, origin.z ) targetPos = GetGroundPosition(targetPos, hero) local unit = CreateUnitByName( KITTY_FLEX_UNIT, spawnPos, true, hero, hero, hero:GetTeamNumber() ) if not unit or unit:IsNull() or not IsValidEntity(unit) then goto __continue142 end FindClearSpaceForUnit(unit, spawnPos, true) unit:AddNewModifier( hero, getModifierSourceAbility(nil, hero), modifier_kitty_flex_catakeet.name, { bounce_radius_min = config.bounceRadiusMin, bounce_radius_max = config.bounceRadiusMax, bounce_height_min = config.bounceHeightMin, bounce_height_max = config.bounceHeightMax, bounce_interval_min = config.bounceIntervalMin, bounce_interval_max = config.bounceIntervalMax, look_interval_min = config.lookIntervalMin, look_interval_max = config.lookIntervalMax } ) local ____self_kittyFlexUnits_6 = self.kittyFlexUnits ____self_kittyFlexUnits_6[#____self_kittyFlexUnits_6 + 1] = unit local throwDistance = (targetPos - spawnPos):Length2D() modifier_general_arc:apply( unit, hero, nil, { x = targetPos.x, y = targetPos.y, z = targetPos.z, duration = config.throwDuration, distance = throwDistance, height = RandomFloat(config.throwHeightMin, config.throwHeightMax), isFlail = true } ) end ::__continue142:: i = i + 1 end end end local function handleKittyFlexSound(____, data) local isKittyFlexSound = data.soundName == "kitty_flex" or data.soundId == "kitty_flex" or data.soundId and __TS__StringIncludes(data.soundId, "kitty_flex") or data.soundName and __TS__StringIncludes(data.soundName, "kitty_flex") if not isKittyFlexSound then return end print(((("[SoundSystem] kitty_flex от игрока " .. tostring(data.playerId)) .. ", запускаем catakeet + screen shake на ") .. tostring(config.effectDuration)) .. " сек") if self.kittyFlexStopTimer then Timers:RemoveTimer(self.kittyFlexStopTimer) self.kittyFlexStopTimer = nil end stopKittyFlexTimers(nil) cleanupKittyFlexCatakeets(nil) local hero = PlayerResource:GetSelectedHeroEntity(data.playerId) local function throwFromHero(____, count) if not hero or not IsValidEntity(hero) or hero:IsNull() or not hero:IsAlive() then return end throwCatakeetsFromHero(nil, hero, count) end throwFromHero(nil, config.initialThrowCount) performScreenShake(nil) self.kittyFlexShakeTimer = Timers:CreateTimer( config.shakeInterval, function() performScreenShake(nil) return config.shakeInterval end ) self.kittyFlexThrowTimer = Timers:CreateTimer( config.throwInterval, function() throwFromHero(nil, config.incrementThrowCount) return config.throwInterval end ) self.kittyFlexStopTimer = Timers:CreateTimer( config.effectDuration, function() print("[SoundSystem] kitty_flex закончился, убираем catakeet, screen shake и броски") stopKittyFlexTimers(nil) cleanupKittyFlexCatakeets(nil) self.kittyFlexStopTimer = nil return nil end ) end ____exports.SoundEventSystem:getInstance():onSound("kitty_flex", handleKittyFlexSound) ____exports.SoundEventSystem:getInstance():onAnySound(handleKittyFlexSound) end function SoundSystemManager.prototype.startRainForAllPlayers(self) local players = self:getAllPlayers() for ____, ____value in ipairs(players) do local player = ____value.player if player ~= nil and player ~= nil then self:setWeatherPlayer(player, "dityRain") end end end function SoundSystemManager.prototype.stopRainForAllPlayers(self) local players = self:getAllPlayers() for ____, ____value in ipairs(players) do local player = ____value.player if player ~= nil and player ~= nil then self:setWeatherPlayer(player, "none") end end end function SoundSystemManager.prototype.getAllPlayers(self) local players = {} do local playerID = 0 while playerID < DOTA_MAX_PLAYERS do do if not PlayerResource:IsValidPlayerID(playerID) then goto __continue161 end local player = PlayerResource:GetPlayer(playerID) if player == nil or player == nil then goto __continue161 end local hero = PlayerResource:GetSelectedHeroEntity(playerID) players[#players + 1] = {player = player, hero = hero or nil} end ::__continue161:: playerID = playerID + 1 end end return players end function SoundSystemManager.prototype.setWeatherPlayer(self, player, ____type) if not player.weatherEffect then player.weatherEffect = {} end local ____player_weatherEffect_7 = player.weatherEffect local sound = ____player_weatherEffect_7.sound local effect = ____player_weatherEffect_7.effect if sound and sound.timer then Timers:RemoveTimer(sound.timer) end if sound then StopGlobalSound(sound.name) end if effect then ParticleManager:DestroyParticle(effect, false) end if ____type == "none" then player.weatherEffect.effect = nil player.weatherEffect.sound = nil return end local weatherEffects = {none = "", desertStorm = "particles/rain_fx/econ_weather_sirocco.vpcf", dityRain = "particles/rain_fx/econ_rain.vpcf", snowstorm = "particles/winter_fx/weather_plateau_snow.vpcf"} local weatherSounds = {none = nil, dityRain = {duration = 175, name = "rain"}, desertStorm = nil, snowstorm = {duration = 140, name = "snowstorm"}} local weatherSound = weatherSounds[____type] if weatherSound then local timer = Timers:CreateTimer({ endTime = 0.1, useGameTime = false, callback = function() EmitGlobalSound(weatherSound.name) return weatherSound.duration end }) player.weatherEffect.sound = {name = weatherSound.name, timer = timer} end local effectPath = weatherEffects[____type] if effectPath ~= nil and effectPath ~= nil and effectPath ~= "" then local hero = PlayerResource:GetSelectedHeroEntity(player:GetPlayerID()) if hero ~= nil and hero ~= nil then local particle = ParticleManager:CreateParticleForPlayer(effectPath, PATTACH_EYES_FOLLOW, hero, player) player.weatherEffect.effect = particle end end end --- Частицы погоды (чат-колесо) function ____exports.precacheWeatherParticles(self, context) PrecacheResource("particle", "particles/rain_fx/econ_weather_sirocco.vpcf", context) PrecacheResource("particle", "particles/rain_fx/econ_weather_pestilence.vpcf", context) PrecacheResource("particle", "particles/winter_fx/weather_plateau_snow.vpcf", context) PrecacheResource("particle", "particles/rain_fx/econ_rain.vpcf", context) end --- Модель catakeet для эффекта kitty_flex function ____exports.precacheKittyFlexResources(self, context) PrecacheResource("model", KITTY_FLEX_CATAKEET_MODEL, context) end return ____exports