local PLUGIN = PLUGIN -- Таблица активных звуков PLUGIN.activeSounds = PLUGIN.activeSounds or {} -- Функция для воспроизведения TTS function PLUGIN:PlayTTS(url, speakerName, speakerPos) -- Проверяем, включен ли звук у игрока if not GetConVar("volume"):GetFloat() or GetConVar("volume"):GetFloat() <= 0 then return end -- Воспроизводим звук через URL sound.PlayURL(url, "3d noblock", function(station, errCode, errStr) if IsValid(station) then -- Устанавливаем позицию звука station:SetPos(speakerPos) -- Добавляем 3D эффект station:Set3DEnabled(true) station:Set3DFadeDistance(50, 500) -- Громкость зависит от расстояния local radius = ix.config.Get("voiceChatRadius", 200) local distance = LocalPlayer():GetPos():Distance(speakerPos) local volume = math.Clamp(1 - (distance / radius), 0.1, 1) station:SetVolume(volume) -- Воспроизводим station:Play() -- Сохраняем ссылку на звук PLUGIN.activeSounds[station] = true -- Показываем индикатор говорящего local hookID = "ixVoiceChat_" .. tostring(SysTime()) hook.Add("HUDPaint", hookID, function() if not IsValid(station) or station:GetState() ~= GMOD_CHANNEL_PLAYING then hook.Remove("HUDPaint", hookID) PLUGIN.activeSounds[station] = nil return end -- Рисуем индикатор в правом верхнем углу local w, h = ScrW(), ScrH() local text = "🔊 " .. speakerName surface.SetFont("ixMenuButtonFont") local tw, th = surface.GetTextSize(text) -- Фон surface.SetDrawColor(0, 0, 0, 200) surface.DrawRect(w - tw - 30, 10, tw + 20, th + 10) -- Текст draw.SimpleText(text, "ixMenuButtonFont", w - tw - 20, 15, Color(100, 255, 100), TEXT_ALIGN_LEFT) end) -- Автоматически останавливаем через 30 секунд (защита от зависания) timer.Simple(30, function() if IsValid(station) then station:Stop() end end) else -- Ошибка загрузки LocalPlayer():ChatPrint(string.format("[TTS] Ошибка загрузки звука: %s (%s)", errStr or "Unknown", errCode or "0")) end end) end -- Получение сетевого сообщения net.Receive("ixVoiceChatPlay", function() local url = net.ReadString() local speakerName = net.ReadString() local speakerPos = net.ReadVector() PLUGIN:PlayTTS(url, speakerName, speakerPos) end) -- Очистка звуков при отключении function PLUGIN:ShutDown() for station, _ in pairs(self.activeSounds) do if IsValid(station) then station:Stop() end end self.activeSounds = {} end -- Команда для проверки статуса TTS concommand.Add("voice_chat_status", function() local character = LocalPlayer():GetCharacter() if not character then LocalPlayer():ChatPrint("[TTS] У вас нет активного персонажа") return end local hasAccess = character:GetData("voice_chat_unlocked", false) if hasAccess then LocalPlayer():ChatPrint("[TTS] ✓ У вас есть доступ к говорилке") LocalPlayer():ChatPrint("[TTS] Используйте !tts <текст> для воспроизведения") else LocalPlayer():ChatPrint("[TTS] ✗ У вас нет доступа к говорилке") LocalPlayer():ChatPrint("[TTS] Приобретите её в F4 меню (Другое → Говорилка)") end end)