921 lines
39 KiB
Lua
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
|