Files
Dota-Zombie-Invasion/scripts/vscripts/soundsystem.lua
T
2026-05-29 15:11:31 +07:00

921 lines
39 KiB
Lua

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