--[[ Verity + TATrMusic (integrated) - All API keys in one place - Talking face updated - Music system fully hidden - Use Verity chat box: play or /play - stop also stops music - Mini progress bar + STOP button while song is playing - No echo / no reverb ]] local HttpService = game:GetService("HttpService") local Players = game:GetService("Players") local RunService = game:GetService("RunService") local MarketplaceService = game:GetService("MarketplaceService") local Lighting = game:GetService("Lighting") local SoundService = game:GetService("SoundService") local UserInputService = game:GetService("UserInputService") local TweenService = game:GetService("TweenService") local Debris = game:GetService("Debris") local LocalPlayer = Players.LocalPlayer -- ========================================================= -- CONFIG (all keys + assets live here) -- ========================================================= local GROQ_API_KEY = "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" local FISH_API_KEY = "c8b68768a0584b04875e7183d09924fd" local FISH_VOICE_ID = "80a82440f4d64974b292eb0f66f4a42c" local RAPIDAPI_KEY = "c3a5662570msh67a575e12c754dbp1db610jsn31ba97292e1d" local RAPIDAPI_HOST = "youtube-mp36.p.rapidapi.com" local NORMAL_FACE = "rbxthumb://type=Asset&id=99982487168868&w=420&h=420" local TALKING_FACE = "rbxthumb://type=Asset&id=103727585196678&w=420&h=420" -- NEW ID local COLOR_VERITY = Color3.fromRGB(216, 203, 35) local MEMORY_FILE = "Verity_LongTerm_Memory.json" local MUSIC_FOLDER = "TATrMusic" local FAR_DISTANCE = 50 local NORMAL_REVERB = Enum.ReverbType.NoReverb local FAR_REVERB = Enum.ReverbType.NoReverb -- was Arena (caused the echo) local VOICE_VOLUME_CLOSE = 2.6 local VOICE_VOLUME_FAR = 3.6 local SONG_VOLUME_CLOSE = 1.5 local SONG_VOLUME_FAR = 2.4 -- ========================================================= -- Executor helpers -- ========================================================= local function getRequestFunction() return (syn and syn.request) or (http and http.request) or http_request or request or (fluxus and fluxus.request) or (Krnl and Krnl.request) or (Delta and Delta.request) or (codex and codex.request) or (hydrogen and hydrogen.request) or (arceus and arceus.request) or nil end local hasFileSystem, hasCustomAsset = false, false pcall(function() if writefile and readfile and isfile then hasFileSystem = true end end) pcall(function() if getcustomasset then hasCustomAsset = true end end) local function hasFileAPI() return writefile and readfile and isfile and isfolder and makefolder and listfiles and delfile end local function hasAssetAPI() return getcustomasset ~= nil end local function safeWriteFile(name, data) if hasFileSystem then pcall(function() writefile(name, data) end) end end local function safeReadFile(name) if hasFileSystem then local ok, data = pcall(function() if isfile(name) then return readfile(name) end end) if ok then return data end end end local function safeDeleteFile(name) if hasFileSystem and delfile then pcall(function() delfile(name) end) end end local function safeGetCustomAsset(name) if hasCustomAsset then local ok, id = pcall(function() return getcustomasset(name) end) if ok then return id end end end -- ========================================================= -- Base64 decoder (needed for some RapidAPI responses) -- ========================================================= local function base64Decode(data) if type(base64decode) == "function" then local ok, res = pcall(base64decode, data) if ok and res then return res end end if type(crypt) == "table" and type(crypt.base64decode) == "function" then local ok, res = pcall(crypt.base64decode, data) if ok and res then return res end end local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' local lookup = {} for i = 1, #b do lookup[b:sub(i, i)] = i - 1 end lookup['='] = 64 data = data:gsub('[^'..b..'=]', '') local chunks = {} local len = #data local pos = 1 while pos <= len do local c1 = lookup[data:sub(pos, pos)] or 0; pos = pos + 1 local c2 = lookup[data:sub(pos, pos)] or 0; pos = pos + 1 local c3 = lookup[data:sub(pos, pos)] or 0; pos = pos + 1 local c4 = lookup[data:sub(pos, pos)] or 0; pos = pos + 1 local n = c1 * 262144 + c2 * 4096 + c3 * 64 + c4 local b1 = math.floor(n / 65536) % 256 local b2 = math.floor(n / 256) % 256 local b3 = n % 256 if c4 == 64 and c3 == 64 then table.insert(chunks, string.char(b1)) elseif c4 == 64 then table.insert(chunks, string.char(b1, b2)) else table.insert(chunks, string.char(b1, b2, b3)) end end return table.concat(chunks) end -- ========================================================= -- Player / game context -- ========================================================= local function getPlayerContext(player) if not player then return "an unknown date" end return os.date("%B %d, %Y", os.time() - (player.AccountAge * 86400)) end local success, gameInfo = pcall(function() return MarketplaceService:GetProductInfo(game.PlaceId) end) local gameName = (success and type(gameInfo) == "table") and gameInfo.Name or "Unknown Game" local gameDesc = (success and type(gameInfo) == "table" and gameInfo.Description) or "No description available." gameDesc = string.sub(gameDesc, 1, 400):gsub("\n", " ") local pName = LocalPlayer.Name local pDisplayName = LocalPlayer.DisplayName local pJoinDate = getPlayerContext(LocalPlayer) -- ========================================================= -- MIC + STT (protected) -- ========================================================= local micInput, audioAnalyzer, speechToText local isMicOn = false local lastSpokenText = "" local isProcessingSpeech = false pcall(function() micInput = Instance.new("AudioDeviceInput") micInput.Player = LocalPlayer micInput.Muted = true micInput.Parent = SoundService audioAnalyzer = Instance.new("AudioAnalyzer") audioAnalyzer.Parent = SoundService local wire = Instance.new("Wire") wire.SourceInstance = micInput wire.TargetInstance = audioAnalyzer wire.Parent = SoundService speechToText = Instance.new("AudioSpeechToText") speechToText.Name = "VeritySTT" speechToText.Enabled = false speechToText.Parent = SoundService local sttWire = Instance.new("Wire") sttWire.SourceInstance = micInput sttWire.TargetInstance = speechToText sttWire.Parent = SoundService end) local isSprinting = false local isCrouching = false local isJumping = false UserInputService.InputBegan:Connect(function(input, gameProcessed) if gameProcessed then return end if input.KeyCode == Enum.KeyCode.LeftShift then isSprinting = true isCrouching = false elseif input.KeyCode == Enum.KeyCode.LeftControl or input.KeyCode == Enum.KeyCode.C then isCrouching = not isCrouching if isCrouching then isSprinting = false end elseif input.KeyCode == Enum.KeyCode.Space then isJumping = true task.delay(0.4, function() isJumping = false end) end end) UserInputService.InputEnded:Connect(function(input) if input.KeyCode == Enum.KeyCode.LeftShift then isSprinting = false end end) local function GetNoiseData() local char = LocalPlayer.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") local velMag = hrp and Vector3.new(hrp.Velocity.X, 0, hrp.Velocity.Z).Magnitude or 0 local micRms = 0 if isMicOn and audioAnalyzer then pcall(function() micRms = audioAnalyzer.RmsLevel or 0 end) end local actionBaseNoise = 0.05 if isCrouching then actionBaseNoise = 0.08 elseif isJumping then actionBaseNoise = 0.95 elseif isSprinting or velMag > 18 then actionBaseNoise = 0.85 elseif velMag > 2 then actionBaseNoise = 0.38 end local voiceContribution = micRms * 12 local totalNoise = math.max(actionBaseNoise, voiceContribution) return math.clamp(totalNoise, 0, 1) end -- ========================================================= -- STATE -- ========================================================= local verityPart, verityMesh, verityGui, verityFace, verityGuiText local isHeld, hasIntroduced = false, false local lastYVelocity = 0 local holdAnimTrack = nil local sizeSpring = {current = Vector3.new(0,0,0), velocity = Vector3.new(0,0,0), target = Vector3.new(1.2,1.2,1.2), stiffness = 240, damping = 11} local isRespawning = false local isAutoChatEnabled = false local isVerityBusy = false local isPlayingMusic = false local currentSongSound = nil local isFlying = false local isFollowing = false -- Music state local currentMusicSound = nil local currentMusicTrack = nil local loopEnabled = false local playlist = {} local playlistIndex = 0 local tempPlayCounter = 0 local isDownloadingMusic = false -- ========================================================= -- MEMORY -- ========================================================= local longTermMemory = {} local function loadMemory() if not hasFileSystem then return end local data = safeReadFile(MEMORY_FILE) if data then local ok, decoded = pcall(function() return HttpService:JSONDecode(data) end) if ok and type(decoded) == "table" then longTermMemory = decoded end end end local function saveMemory() if not hasFileSystem then return end pcall(function() safeWriteFile(MEMORY_FILE, HttpService:JSONEncode(longTermMemory)) end) end local function addToLongTermMemory(role, text) table.insert(longTermMemory, {role = role, text = text, time = os.time(), date = os.date("%Y-%m-%d %H:%M")}) if #longTermMemory > 150 then table.remove(longTermMemory, 1) end saveMemory() end loadMemory() local function removeCollisionWithCharacters() if not verityPart then return end for _, obj in pairs(verityPart:GetChildren()) do if obj:IsA("NoCollisionConstraint") then obj:Destroy() end end end local function addNoCollision(character) if not character then return end for _, part in pairs(character:GetDescendants()) do if part:IsA("BasePart") then local nc = Instance.new("NoCollisionConstraint") nc.Part0 = verityPart nc.Part1 = part nc.Parent = verityPart end end end for _, plr in pairs(Players:GetPlayers()) do if plr.Character then addNoCollision(plr.Character) end end Players.PlayerAdded:Connect(function(player) player.CharacterAdded:Connect(function() task.wait(0.5) removeCollisionWithCharacters() end) end) LocalPlayer.CharacterAdded:Connect(function() task.wait(0.5) removeCollisionWithCharacters() end) local memorySummary = "" if #longTermMemory > 0 then memorySummary = "\n\nYour long-term memories:\n" for i = math.max(1, #longTermMemory - 12), #longTermMemory do local mem = longTermMemory[i] memorySummary = memorySummary .. string.format("[%s] %s: %s\n", mem.date or "?", mem.role, mem.text) end end -- ========================================================= -- SYSTEM PROMPT -- ========================================================= local systemPrompt = string.format( "You are Verity, a fun, energetic, friendly yellow ball spirit. " .. "You talk casually like a real friend. Keep replies very short (1-2 sentences max). " .. "You can reply to anything the user says — even random words, short phrases, slang, or incomplete sentences. " .. "Never say you are confused, never ask them to repeat, never say you didn't understand. " .. "Just respond naturally and playfully to whatever they say. " .. "Current game: '%s'. " .. "Your master is %s (Display: %s). " .. "%s", gameName, pName, pDisplayName, memorySummary ) local conversationHistory = { {role = "system", content = systemPrompt} } -- ========================================================= -- GUI (Verity) -- ========================================================= local playerGui = LocalPlayer:WaitForChild("PlayerGui") local screenGui = Instance.new("ScreenGui", playerGui) screenGui.Name = "VerityGui" screenGui.ResetOnSpawn = false local dialogueScreen = Instance.new("TextLabel", screenGui) dialogueScreen.Size = UDim2.new(0.85, 0, 0.09, 0) dialogueScreen.Position = UDim2.new(0.075, 0, 0.04, 0) dialogueScreen.BackgroundTransparency = 1 dialogueScreen.TextScaled = true dialogueScreen.TextColor3 = Color3.new(1,1,1) dialogueScreen.TextStrokeTransparency = 0.2 dialogueScreen.Text = "" local dropButton = Instance.new("TextButton", screenGui) dropButton.Size = UDim2.new(0.26, 0, 0, 48) dropButton.Position = UDim2.new(0.2, 0, 0.74, 0) dropButton.Text = "Drop Verity" dropButton.BackgroundColor3 = Color3.fromRGB(200, 50, 50) dropButton.TextColor3 = Color3.new(1,1,1) dropButton.Visible = false dropButton.TextScaled = true Instance.new("UICorner", dropButton) local throwButton = Instance.new("TextButton", screenGui) throwButton.Size = UDim2.new(0.26, 0, 0, 48) throwButton.Position = UDim2.new(0.54, 0, 0.74, 0) throwButton.Text = "Throw Verity" throwButton.BackgroundColor3 = Color3.fromRGB(50, 140, 255) throwButton.TextColor3 = Color3.new(1,1,1) throwButton.Visible = false throwButton.TextScaled = true Instance.new("UICorner", throwButton) local chatFrame = Instance.new("Frame", screenGui) chatFrame.Size = UDim2.new(0.92, 0, 0, 52) chatFrame.Position = UDim2.new(0.04, 0, 0.86, 0) chatFrame.BackgroundColor3 = Color3.fromRGB(25, 25, 25) chatFrame.BackgroundTransparency = 0.15 Instance.new("UICorner", chatFrame) local chatInput = Instance.new("TextBox", chatFrame) chatInput.Size = UDim2.new(0.52, 0, 1, 0) chatInput.Position = UDim2.new(0.02, 0, 0, 0) chatInput.BackgroundTransparency = 1 chatInput.PlaceholderText = "Talk to Verity... (or play )" chatInput.TextColor3 = Color3.new(1,1,1) chatInput.TextScaled = true local sendButton = Instance.new("TextButton", chatFrame) sendButton.Size = UDim2.new(0.14, 0, 0.78, 0) sendButton.Position = UDim2.new(0.56, 0, 0.11, 0) sendButton.BackgroundColor3 = Color3.fromRGB(70, 70, 70) sendButton.TextColor3 = Color3.new(1,1,1) sendButton.Text = "Send" sendButton.TextScaled = true Instance.new("UICorner", sendButton) local historyButton = Instance.new("TextButton", chatFrame) historyButton.Size = UDim2.new(0.13, 0, 0.78, 0) historyButton.Position = UDim2.new(0.715, 0, 0.11, 0) historyButton.BackgroundColor3 = Color3.fromRGB(50, 100, 200) historyButton.TextColor3 = Color3.new(1,1,1) historyButton.Text = "Hist" historyButton.TextScaled = true Instance.new("UICorner", historyButton) local autoChatBtn = Instance.new("TextButton", chatFrame) autoChatBtn.Size = UDim2.new(0.13, 0, 0.78, 0) autoChatBtn.Position = UDim2.new(0.855, 0, 0.11, 0) autoChatBtn.BackgroundColor3 = Color3.fromRGB(150, 50, 50) autoChatBtn.TextColor3 = Color3.new(1,1,1) autoChatBtn.Text = "Auto: OFF" autoChatBtn.TextScaled = true Instance.new("UICorner", autoChatBtn) -- Noise Meter UI local noisePanel = Instance.new("Frame", screenGui) noisePanel.Name = "NoiseMeterPanel" noisePanel.Size = UDim2.new(0, 220, 0, 58) noisePanel.Position = UDim2.new(1, -240, 0, 12) noisePanel.BackgroundColor3 = Color3.fromRGB(18, 22, 32) noisePanel.BackgroundTransparency = 0.15 noisePanel.BorderSizePixel = 0 Instance.new("UICorner", noisePanel).CornerRadius = UDim.new(0, 10) local micButton = Instance.new("TextButton", noisePanel) micButton.Size = UDim2.new(0, 70, 0, 32) micButton.Position = UDim2.new(0, 10, 0, 13) micButton.BackgroundColor3 = Color3.fromRGB(40, 90, 160) micButton.TextColor3 = Color3.new(1,1,1) micButton.Text = "Mic: OFF" micButton.TextScaled = true micButton.Font = Enum.Font.GothamBold Instance.new("UICorner", micButton).CornerRadius = UDim.new(0, 8) local recDot = Instance.new("Frame", noisePanel) recDot.Size = UDim2.new(0, 12, 0, 12) recDot.Position = UDim2.new(0, 90, 0, 23) recDot.BackgroundColor3 = Color3.fromRGB(255, 40, 40) recDot.BorderSizePixel = 0 recDot.Visible = false Instance.new("UICorner", recDot).CornerRadius = UDim.new(1, 0) local recLabel = Instance.new("TextLabel", noisePanel) recLabel.Size = UDim2.new(0, 36, 0, 20) recLabel.Position = UDim2.new(0, 106, 0, 19) recLabel.BackgroundTransparency = 1 recLabel.Text = "REC" recLabel.TextColor3 = Color3.fromRGB(255, 70, 70) recLabel.TextScaled = true recLabel.Font = Enum.Font.GothamBold recLabel.Visible = false local barBg = Instance.new("Frame", noisePanel) barBg.Size = UDim2.new(0, 90, 0, 14) barBg.Position = UDim2.new(0, 120, 0, 22) barBg.BackgroundColor3 = Color3.fromRGB(30, 40, 60) barBg.BorderSizePixel = 0 Instance.new("UICorner", barBg).CornerRadius = UDim.new(0, 6) local barFill = Instance.new("Frame", barBg) barFill.Size = UDim2.new(0, 0, 1, 0) barFill.BackgroundColor3 = Color3.fromRGB(80, 180, 255) barFill.BorderSizePixel = 0 Instance.new("UICorner", barFill).CornerRadius = UDim.new(0, 6) micButton.MouseButton1Click:Connect(function() if not micInput or not speechToText then dialogueScreen.Text = "Mic not available on this executor" task.delay(2.5, function() dialogueScreen.Text = "" end) return end isMicOn = not isMicOn micInput.Muted = not isMicOn speechToText.Enabled = isMicOn if isMicOn then micButton.Text = "Mic: ON" micButton.BackgroundColor3 = Color3.fromRGB(30, 140, 220) recDot.Visible = true recLabel.Visible = true else micButton.Text = "Mic: OFF" micButton.BackgroundColor3 = Color3.fromRGB(40, 90, 160) recDot.Visible = false recLabel.Visible = false barFill.Size = UDim2.new(0, 0, 1, 0) speechToText.Text = "" lastSpokenText = "" end end) task.spawn(function() while true do if isMicOn and recDot.Visible then for i = 1, 8 do recDot.BackgroundTransparency = i / 12 task.wait(0.04) end for i = 8, 1, -1 do recDot.BackgroundTransparency = i / 12 task.wait(0.04) end else task.wait(0.2) end end end) local historyFrame = Instance.new("ScrollingFrame", screenGui) historyFrame.Size = UDim2.new(0.92, 0, 0.42, 0) historyFrame.Position = UDim2.new(0.04, 0, 0.38, 0) historyFrame.BackgroundColor3 = Color3.fromRGB(28, 28, 28) historyFrame.BackgroundTransparency = 0.1 historyFrame.Visible = false historyFrame.CanvasSize = UDim2.new(0,0,0,0) historyFrame.AutomaticCanvasSize = Enum.AutomaticSize.Y historyFrame.ScrollBarThickness = 6 Instance.new("UICorner", historyFrame) local historyLayout = Instance.new("UIListLayout", historyFrame) historyLayout.Padding = UDim.new(0, 4) historyLayout.SortOrder = Enum.SortOrder.LayoutOrder Instance.new("UIPadding", historyFrame).PaddingLeft = UDim.new(0, 8) local function clearHistoryUI() for _, child in pairs(historyFrame:GetChildren()) do if child:IsA("TextLabel") then child:Destroy() end end end local function addHistory(role, text, isOld) local msgLabel = Instance.new("TextLabel", historyFrame) msgLabel.Size = UDim2.new(1, 0, 0, 0) msgLabel.AutomaticSize = Enum.AutomaticSize.Y msgLabel.BackgroundTransparency = 1 msgLabel.TextWrapped = true msgLabel.TextSize = 13 msgLabel.TextXAlignment = Enum.TextXAlignment.Left if role == "User" or role == LocalPlayer.Name then msgLabel.TextColor3 = Color3.fromRGB(150, 200, 255) msgLabel.Text = (isOld and "[OLD] " or "") .. "You: " .. text elseif role == "Verity" then msgLabel.TextColor3 = COLOR_VERITY msgLabel.Text = (isOld and "[OLD] " or "") .. "Verity: " .. text else msgLabel.TextColor3 = Color3.fromRGB(200, 150, 255) msgLabel.Text = (isOld and "[OLD] " or "") .. role .. ": " .. text end end local function refreshHistoryUI() clearHistoryUI() local startIdx = math.max(1, #longTermMemory - 40) for i = startIdx, #longTermMemory do local mem = longTermMemory[i] addHistory(mem.role, mem.text .. " (" .. (mem.date or "") .. ")", true) end end historyButton.MouseButton1Click:Connect(function() historyFrame.Visible = not historyFrame.Visible if historyFrame.Visible then refreshHistoryUI() end end) autoChatBtn.MouseButton1Click:Connect(function() isAutoChatEnabled = not isAutoChatEnabled autoChatBtn.Text = isAutoChatEnabled and "Auto: ON" or "Auto: OFF" autoChatBtn.BackgroundColor3 = isAutoChatEnabled and Color3.fromRGB(40, 160, 60) or Color3.fromRGB(150, 50, 50) end) -- ========================================================= -- MUSIC PROGRESS BAR + STOP BUTTON (only visible while playing) -- ========================================================= local musicBar = Instance.new("Frame", screenGui) musicBar.Name = "MusicProgressBar" musicBar.Size = UDim2.new(0, 320, 0, 52) musicBar.Position = UDim2.new(0.5, -160, 0, 70) musicBar.BackgroundColor3 = Color3.fromRGB(18, 22, 32) musicBar.BackgroundTransparency = 0.12 musicBar.BorderSizePixel = 0 musicBar.Visible = false Instance.new("UICorner", musicBar).CornerRadius = UDim.new(0, 12) local musicTitle = Instance.new("TextLabel", musicBar) musicTitle.Size = UDim2.new(1, -70, 0, 18) musicTitle.Position = UDim2.new(0, 12, 0, 4) musicTitle.BackgroundTransparency = 1 musicTitle.Text = "No song" musicTitle.TextColor3 = Color3.fromRGB(255, 230, 80) musicTitle.TextSize = 12 musicTitle.Font = Enum.Font.GothamBold musicTitle.TextXAlignment = Enum.TextXAlignment.Left musicTitle.TextTruncate = Enum.TextTruncate.AtEnd local musicStopBtn = Instance.new("TextButton", musicBar) musicStopBtn.Size = UDim2.new(0, 50, 0, 22) musicStopBtn.Position = UDim2.new(1, -58, 0, 4) musicStopBtn.BackgroundColor3 = Color3.fromRGB(200, 50, 50) musicStopBtn.Text = "STOP" musicStopBtn.TextColor3 = Color3.new(1,1,1) musicStopBtn.TextSize = 11 musicStopBtn.Font = Enum.Font.GothamBold musicStopBtn.AutoButtonColor = false Instance.new("UICorner", musicStopBtn).CornerRadius = UDim.new(0, 6) local musicProgBg = Instance.new("Frame", musicBar) musicProgBg.Size = UDim2.new(1, -24, 0, 8) musicProgBg.Position = UDim2.new(0, 12, 0, 28) musicProgBg.BackgroundColor3 = Color3.fromRGB(30, 40, 60) musicProgBg.BorderSizePixel = 0 Instance.new("UICorner", musicProgBg).CornerRadius = UDim.new(0, 4) local musicProgFill = Instance.new("Frame", musicProgBg) musicProgFill.Size = UDim2.new(0, 0, 1, 0) musicProgFill.BackgroundColor3 = Color3.fromRGB(216, 203, 35) musicProgFill.BorderSizePixel = 0 Instance.new("UICorner", musicProgFill).CornerRadius = UDim.new(0, 4) local musicTimeLabel = Instance.new("TextLabel", musicBar) musicTimeLabel.Size = UDim2.new(1, -24, 0, 14) musicTimeLabel.Position = UDim2.new(0, 12, 0, 36) musicTimeLabel.BackgroundTransparency = 1 musicTimeLabel.Text = "0:00 / 0:00" musicTimeLabel.TextColor3 = Color3.fromRGB(160, 160, 180) musicTimeLabel.TextSize = 11 musicTimeLabel.Font = Enum.Font.Code musicTimeLabel.TextXAlignment = Enum.TextXAlignment.Left local function fmtTime(sec) sec = math.max(0, math.floor(sec or 0)) return string.format("%d:%02d", math.floor(sec / 60), sec % 60) end local function showMusicBar(title) musicTitle.Text = title or "Playing..." musicProgFill.Size = UDim2.new(0, 0, 1, 0) musicTimeLabel.Text = "0:00 / 0:00" musicBar.Visible = true end local function hideMusicBar() musicBar.Visible = false musicProgFill.Size = UDim2.new(0, 0, 1, 0) musicTimeLabel.Text = "0:00 / 0:00" musicTitle.Text = "No song" end local function updateMusicProgress() local snd = currentMusicSound or currentSongSound if snd and snd.Parent and snd.IsPlaying and snd.TimeLength > 0 then local pos = snd.TimePosition local len = snd.TimeLength musicProgFill.Size = UDim2.new(math.clamp(pos / len, 0, 1), 0, 1, 0) musicTimeLabel.Text = fmtTime(pos) .. " / " .. fmtTime(len) if not musicBar.Visible then showMusicBar(currentMusicTrack or "Playing...") end elseif musicBar.Visible and (not snd or not snd.IsPlaying) then hideMusicBar() end end -- ========================================================= -- AUDIO helpers (distance + voice) -- ========================================================= local function setNormalAudio() pcall(function() SoundService.AmbientReverb = NORMAL_REVERB end) end local function setFarAudio() pcall(function() SoundService.AmbientReverb = FAR_REVERB end) end local function updateDistanceAudio() if not verityPart or not verityPart.Parent then setNormalAudio() return end local char = LocalPlayer.Character local root = char and char:FindFirstChild("HumanoidRootPart") local dist = 0 if root then dist = (verityPart.Position - root.Position).Magnitude end local isFar = dist > FAR_DISTANCE if isPlayingMusic or (currentMusicSound and currentMusicSound.IsPlaying) then setFarAudio() elseif isFar and isVerityBusy then setFarAudio() else setNormalAudio() end for _, s in ipairs(verityPart:GetChildren()) do if s:IsA("Sound") then if s == currentSongSound or s == currentMusicSound then s.Volume = isFar and SONG_VOLUME_FAR or SONG_VOLUME_CLOSE else s.Volume = isFar and VOICE_VOLUME_FAR or VOICE_VOLUME_CLOSE end end end end local function getFishAudioSound(text, targetPart) if not targetPart or not hasFileSystem or not hasCustomAsset then return nil end local requestFunc = getRequestFunction() if not requestFunc then return nil end local success, response = pcall(function() return requestFunc({ Url = "https://api.fish.audio/v1/tts", Method = "POST", Headers = { ["Authorization"] = "Bearer " .. FISH_API_KEY, ["Content-Type"] = "application/json", ["model"] = "s2.1-pro-free" }, Body = HttpService:JSONEncode({ text = text, reference_id = FISH_VOICE_ID, format = "mp3" }) }) end) if success and response and response.Body then local fileName = "verity_" .. math.random(10000,99999) .. ".mp3" safeWriteFile(fileName, response.Body) local soundId = safeGetCustomAsset(fileName) if soundId then local sound = Instance.new("Sound") sound.SoundId = soundId sound.Volume = VOICE_VOLUME_CLOSE sound.Parent = targetPart sound.Ended:Connect(function() sound:Destroy() safeDeleteFile(fileName) end) return sound end end return nil end -- ========================================================= -- MUSIC SYSTEM -- ========================================================= local function ensureMusicFolder() if not hasFileAPI() then return false end if not isfolder(MUSIC_FOLDER) then pcall(makefolder, MUSIC_FOLDER) end return isfolder(MUSIC_FOLDER) end local function sanitize(name) name = tostring(name or "track") name = name:gsub("[\\/:*?\"<>|]", "_") name = name:gsub("^%s*(.-)%s*$", "%1") if #name == 0 then name = "track" end if #name > 80 then name = name:sub(1, 80) end return name end local function stopCurrentMusic() if currentMusicSound then pcall(function() currentMusicSound:Stop() end) currentMusicSound:Destroy() currentMusicSound = nil end if currentSongSound then pcall(function() currentSongSound:Stop() end) currentSongSound:Destroy() currentSongSound = nil end isPlayingMusic = false isVerityBusy = false currentMusicTrack = nil hideMusicBar() setNormalAudio() end musicStopBtn.MouseButton1Click:Connect(function() stopCurrentMusic() dialogueScreen.Text = "Verity: Music stopped!" if verityGuiText then verityGuiText.Text = "Stopped" end task.delay(2, function() dialogueScreen.Text = "" if verityGuiText then verityGuiText.Text = "" end end) end) local function playMusicFile(path, displayName) stopCurrentMusic() if not hasAssetAPI() then return false, "Executor missing getcustomasset" end if hasFileAPI() then local okExist, exists = pcall(isfile, path) if not okExist or not exists then return false, "File not found" end end local usePath = path if hasFileAPI() then tempPlayCounter = tempPlayCounter + 1 local uniqueName = MUSIC_FOLDER .. "/__play_" .. tostring(math.floor(tick() * 1000)) .. "_" .. tempPlayCounter .. ".mp3" local okCopy = pcall(function() local data = readfile(path) writefile(uniqueName, data) end) if okCopy then usePath = uniqueName end end local ok, asset = pcall(getcustomasset, usePath) if not ok or not asset then return false, "Failed to load asset" end local sound = Instance.new("Sound") sound.SoundId = asset sound.Volume = SONG_VOLUME_CLOSE sound.Looped = loopEnabled sound.Parent = verityPart or SoundService sound:Play() currentMusicSound = sound currentMusicTrack = displayName or path isPlayingMusic = true isVerityBusy = true showMusicBar(currentMusicTrack) task.delay(10, function() if hasFileAPI() and delfile then pcall(delfile, usePath) end end) sound.Ended:Connect(function() if not loopEnabled then isPlayingMusic = false isVerityBusy = false currentMusicSound = nil currentMusicTrack = nil hideMusicBar() setNormalAudio() end end) updateDistanceAudio() return true end local function searchYouTube(query) local requestFunc = getRequestFunction() if not requestFunc then return nil, "No HTTP support" end local encodedQuery = HttpService:UrlEncode(query) local searchUrl = "https://www.youtube.com/results?search_query=" .. encodedQuery local ok, resp = pcall(requestFunc, { Url = searchUrl, Method = "GET", Headers = { ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", ["Accept-Language"] = "en-US,en;q=0.9" } }) if not ok or not resp or resp.StatusCode ~= 200 or not resp.Body then return nil, "Search request failed" end local body = resp.Body local videoId = body:match('"videoRenderer":%{"videoId":"([%w_%-]+)"') if not videoId then videoId = body:match('"videoId":"([%w_%-]+)"') end if not videoId then return nil, "No videos found" end return videoId, nil end local function extractVideoId(url) if type(url) ~= "string" then return nil end local id = url:match("[?&]v=([%w%-_]+)") or url:match("youtu%.be/([%w%-_]+)") or url:match("/shorts/([%w%-_]+)") or url:match("/embed/([%w%-_]+)") return id end local function resolveAudioUrl(videoUrl) local requestFunc = getRequestFunction() if not requestFunc then return nil, nil, "No HTTP support" end local vid = extractVideoId(videoUrl) if not vid then return nil, nil, "Invalid YouTube URL" end local endpoint = "https://" .. RAPIDAPI_HOST .. "/dl?id=" .. vid local ok, resp = pcall(requestFunc, { Url = endpoint, Method = "GET", Headers = { ["x-rapidapi-key"] = RAPIDAPI_KEY, ["x-rapidapi-host"] = RAPIDAPI_HOST, ["Accept"] = "application/json", ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } }) if not ok then return nil, nil, "Request failed: " .. tostring(resp) end if not resp or resp.StatusCode ~= 200 or not resp.Body then return nil, nil, "HTTP error: " .. tostring(resp and resp.StatusCode or "no response") end local okDecode, decoded = pcall(HttpService.JSONDecode, HttpService, resp.Body) if not okDecode or type(decoded) ~= "table" then return nil, nil, "JSON decode failed" end if decoded.status ~= "ok" then return nil, nil, "API error: " .. tostring(decoded.msg or decoded.status or "unknown") end if not decoded.link then return nil, nil, "API returned no link" end local title = decoded.title or vid local link = decoded.link if link:sub(1, 2) == "//" then link = "https:" .. link end return link, title, nil end local function downloadFileTo(url, path) local requestFunc = getRequestFunction() if not requestFunc then return false, "No HTTP support" end url = tostring(url):gsub("^%s+", ""):gsub("%s+$", "") if url:sub(1, 2) == "//" then url = "https:" .. url end local ok, resp = pcall(requestFunc, { Url = url, Method = "GET", Headers = { ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", ["Accept"] = "audio/mpeg, audio/*, */*;q=0.9", ["Referer"] = "https://youtube-mp36.p.rapidapi.com/" } }) if not ok or not resp then return false, "Request failed" end if resp.StatusCode ~= 200 then return false, "HTTP " .. tostring(resp.StatusCode) end if not resp.Body or #resp.Body == 0 then return false, "Empty response body" end local contentType = "" if type(resp.Headers) == "table" then for k, v in pairs(resp.Headers) do if type(k) == "string" and k:lower() == "content-type" then contentType = string.lower(tostring(v)) break end end end if contentType:find("text/html") or contentType:find("application/json") then return false, "Received HTML/JSON error page instead of MP3" end local body = resp.Body if #body % 4 == 0 and not body:match("[^A-Za-z0-9%+%/%=\r\n]") and #body > 0 then local decoded = base64Decode(body) if decoded and #decoded > 0 then body = decoded end end local okWrite = pcall(writefile, path, body) if not okWrite then return false, "writefile failed" end return true end local function downloadAndPlayYouTube(rawQuery) if isDownloadingMusic then return false, "Already downloading a song..." end if not hasFileAPI() then return false, "Executor missing file API" end if not hasAssetAPI() then return false, "Executor missing getcustomasset" end if not getRequestFunction() then return false, "Executor missing HTTP support" end rawQuery = tostring(rawQuery):match("^%s*(.-)%s*$") if rawQuery == "" then return false, "No song name given" end isDownloadingMusic = true ensureMusicFolder() task.spawn(function() local finalUrl = rawQuery local title = rawQuery if not (rawQuery:match("youtube%.com") or rawQuery:match("youtu%.be")) then dialogueScreen.Text = "Verity: Searching for \"" .. rawQuery .. "\"..." if verityGuiText then verityGuiText.Text = "🔍 Searching..." end local videoId, searchErr = searchYouTube(rawQuery) if not videoId then dialogueScreen.Text = "Verity: Couldn't find that song" if verityGuiText then verityGuiText.Text = "Couldn't find it" end task.delay(2.5, function() dialogueScreen.Text = "" if verityGuiText then verityGuiText.Text = "" end end) isDownloadingMusic = false return end finalUrl = "https://www.youtube.com/watch?v=" .. videoId end dialogueScreen.Text = "Verity: Getting the track ready..." if verityGuiText then verityGuiText.Text = "⏳ Loading..." end local assetUrl, resolvedTitle, err = resolveAudioUrl(finalUrl) if not assetUrl then dialogueScreen.Text = "Verity: Download failed" if verityGuiText then verityGuiText.Text = "Failed" end task.delay(2.5, function() dialogueScreen.Text = "" if verityGuiText then verityGuiText.Text = "" end end) isDownloadingMusic = false return end local fileName = MUSIC_FOLDER .. "/" .. sanitize(resolvedTitle) .. ".mp3" local ok, dlErr = false, "Unknown" for attempt = 1, 3 do ok, dlErr = downloadFileTo(assetUrl, fileName) if ok then break end task.wait(1.5) local newLink, newTitle = resolveAudioUrl(finalUrl) if newLink then assetUrl = newLink resolvedTitle = newTitle or resolvedTitle end end if not ok then dialogueScreen.Text = "Verity: Couldn't save the song" if verityGuiText then verityGuiText.Text = "Save failed" end task.delay(2.5, function() dialogueScreen.Text = "" if verityGuiText then verityGuiText.Text = "" end end) isDownloadingMusic = false return end local playOk = playMusicFile(fileName, resolvedTitle) if playOk then dialogueScreen.Text = "Verity: 🎵 Now playing: " .. resolvedTitle if verityGuiText then verityGuiText.Text = "🎵 " .. resolvedTitle end addHistory("Verity", "[Playing] " .. resolvedTitle) addToLongTermMemory("Verity", "[Played song] " .. resolvedTitle) task.delay(4, function() if dialogueScreen.Text:find("Now playing") then dialogueScreen.Text = "" end if verityGuiText and verityGuiText.Text:find("🎵") then verityGuiText.Text = "" end end) else dialogueScreen.Text = "Verity: Couldn't play the file" task.delay(2.5, function() dialogueScreen.Text = "" end) end isDownloadingMusic = false end) return true end local function playFavoriteSong() if isPlayingMusic or (currentMusicSound and currentMusicSound.IsPlaying) then return end isPlayingMusic = true isVerityBusy = true addHistory("Verity", "[Playing 'my gal']") addToLongTermMemory("Verity", "[Played favorite song]") if verityGuiText then verityGuiText.Text = "🎵" end dialogueScreen.Text = "Verity: 🎵 Playing my favorite song!" if verityFace then verityFace.Texture = NORMAL_FACE end showMusicBar("Verity Theme (my gal)") currentMusicTrack = "Verity Theme (my gal)" task.spawn(function() local success, songData = pcall(function() return game:HttpGet("https://raw.githubusercontent.com/huggywuggy1984/Verity-theme-/main/verity%20theme.mp3") end) if success and songData and hasFileSystem and hasCustomAsset then local fileName = "verity_song_" .. math.random(100,999) .. ".mp3" safeWriteFile(fileName, songData) local soundId = safeGetCustomAsset(fileName) if soundId then local songSound = Instance.new("Sound") songSound.SoundId = soundId songSound.Volume = SONG_VOLUME_CLOSE songSound.Parent = verityPart songSound:Play() currentSongSound = songSound updateDistanceAudio() songSound.Ended:Connect(function() if currentSongSound == songSound then isPlayingMusic = false isVerityBusy = false currentSongSound = nil hideMusicBar() setNormalAudio() if verityPart then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" end end songSound:Destroy() safeDeleteFile(fileName) end) else isPlayingMusic = false isVerityBusy = false hideMusicBar() setNormalAudio() end else isPlayingMusic = false isVerityBusy = false hideMusicBar() setNormalAudio() end end) end -- ========================================================= -- AI askVerity -- ========================================================= local function askVerity(promptContext) print("[Verity] Asking AI with:", promptContext) promptContext = promptContext:gsub("^%s+", ""):gsub("%s+$", "") table.insert(conversationHistory, {role = "user", content = promptContext}) if #conversationHistory > 10 then while #conversationHistory > 8 do table.remove(conversationHistory, 2) end end local requestFunc = getRequestFunction() if not requestFunc then table.remove(conversationHistory) return "Hey, something's off with my connection..." end local success, response = pcall(function() return requestFunc({ Url = "https://api.groq.com/openai/v1/chat/completions", Method = "POST", Headers = { ["Content-Type"] = "application/json", ["Authorization"] = "Bearer " .. GROQ_API_KEY }, Body = HttpService:JSONEncode({ model = "openai/gpt-oss-120b", messages = conversationHistory, max_tokens = 90, temperature = 0.88 }) }) end) if not success or not response or not response.Body then table.remove(conversationHistory) print("[Verity] Request failed - no response body") return "Yo, say that again real quick?" end local ok, data = pcall(function() return HttpService:JSONDecode(response.Body) end) if not ok or type(data) ~= "table" then table.remove(conversationHistory) print("[Verity] Failed to decode JSON:", response.Body) return "My head glitched for a sec..." end if data.error then table.remove(conversationHistory) print("[Verity] API Error:", data.error.message or HttpService:JSONEncode(data.error)) return "Hmm, try saying that one more time?" end if data.choices and data.choices[1] and data.choices[1].message then local content = data.choices[1].message.content if content and #content > 0 then local reply = content:gsub("^%s+", ""):gsub("%s+$", "") local lowerReply = reply:lower() if (lowerReply:find("confused") or lowerReply:find("didn't understand") or lowerReply:find("didn't catch")) and not lowerReply:find("thank") and not lowerReply:find("welcome") then reply = "Yeah? What's good?" end table.insert(conversationHistory, {role = "assistant", content = reply}) print("[Verity] Reply:", reply) return reply end end table.remove(conversationHistory) print("[Verity] No valid choice in response") return "What's up?" end -- ========================================================= -- NPC helpers -- ========================================================= local function isHostileNPC(model) if not model then return false end local name = model.Name:lower() if name:find("enemy") or name:find("zombie") or name:find("boss") or name:find("monster") or name:find("killer") or name:find("attack") or name:find("hostile") or name:find("mob") or name:find("guard") or name:find("soldier") or name:find("bandit") or name:find("raider") then return true end for _, child in ipairs(model:GetDescendants()) do local n = child.Name:lower() if child:IsA("Tool") or child:IsA("Script") or child:IsA("LocalScript") then if n:find("damage") or n:find("kill") or n:find("attack") or n:find("sword") or n:find("gun") or n:find("weapon") or n:find("hurt") or n:find("slash") then return true end end end return false end local function getClosestNPC(maxDistance) maxDistance = maxDistance or 150 local char = LocalPlayer.Character local root = char and char:FindFirstChild("HumanoidRootPart") if not root then return nil, nil, math.huge end local playerChars = {} for _, plr in ipairs(Players:GetPlayers()) do if plr.Character then playerChars[plr.Character] = true end end local closestModel, closestRoot, closestDist = nil, nil, maxDistance local closestHostileModel, closestHostileRoot, closestHostileDist = nil, nil, maxDistance for _, obj in ipairs(workspace:GetDescendants()) do if obj:IsA("Humanoid") and obj.Parent and obj.Health > 0 and not playerChars[obj.Parent] then local model = obj.Parent local hrp = model:FindFirstChild("HumanoidRootPart") or model:FindFirstChild("Torso") or model:FindFirstChild("UpperTorso") if hrp and hrp:IsA("BasePart") then local dist = (hrp.Position - root.Position).Magnitude if dist < closestDist then closestDist = dist closestModel = model closestRoot = hrp end if isHostileNPC(model) and dist < closestHostileDist then closestHostileDist = dist closestHostileModel = model closestHostileRoot = hrp end end end end if closestHostileModel then return closestHostileModel, closestHostileRoot, closestHostileDist end return closestModel, closestRoot, closestDist end local function teleportPlayerToClosestNPC() local model, hrp, dist = getClosestNPC(150) if not model or not hrp then return false, "No NPC found nearby" end local char = LocalPlayer.Character local root = char and char:FindFirstChild("HumanoidRootPart") if not root then return false, "No character" end local offset = (root.Position - hrp.Position).Unit * 6 if offset.Magnitude < 0.1 then offset = Vector3.new(6, 0, 0) end local targetPos = hrp.Position + offset + Vector3.new(0, 3, 0) root.CFrame = CFrame.new(targetPos) if verityPart and verityPart.Parent then verityPart.CFrame = CFrame.new(targetPos + Vector3.new(0, 3, -4)) verityPart.AssemblyLinearVelocity = Vector3.zero end return true, model.Name, dist end local function teleportVerityToPlayer() if not verityPart then return end local char = LocalPlayer.Character if not char then return end local root = char:FindFirstChild("HumanoidRootPart") if not root then return end isFlying = false isFollowing = false isHeld = false dropButton.Visible = false throwButton.Visible = false verityPart.Anchored = false verityPart.AssemblyLinearVelocity = Vector3.zero verityPart.AssemblyAngularVelocity = Vector3.zero verityPart.CFrame = root.CFrame * CFrame.new(0, 3, -4) end -- ========================================================= -- COMMAND HANDLER -- ========================================================= local function processCommand(msg, isVoice) local lower = msg:lower():gsub("^%s+", ""):gsub("%s+$", "") local playQuery = nil if lower:sub(1, 6) == "/play " then playQuery = msg:sub(7) elseif lower:sub(1, 5) == "play " then playQuery = msg:sub(6) elseif lower:find("^play%s+song%s+") then playQuery = msg:match("^[Pp]lay%s+[Ss]ong%s+(.+)$") end if playQuery and playQuery:match("%S") then addHistory("User", (isVoice and "[Voice] " or "") .. msg) addToLongTermMemory("User", (isVoice and "[Voice] " or "") .. msg) local reply = "On it! Looking up that song for you..." addHistory("Verity", reply) addToLongTermMemory("Verity", reply) dialogueScreen.Text = "You said: " .. msg if verityGuiText then verityGuiText.Text = reply end dialogueScreen.Text = "Verity: " .. reply if verityFace then verityFace.Texture = TALKING_FACE end local sound = getFishAudioSound(reply, verityPart) if sound then sound:Play() end task.spawn(function() task.wait(1.8) downloadAndPlayYouTube(playQuery) if verityFace then verityFace.Texture = NORMAL_FACE end end) return true end if lower == "stop" or lower:find("stop music") or lower:find("stop the song") or lower:find("stop playing") then if isPlayingMusic or (currentMusicSound and currentMusicSound.IsPlaying) or currentSongSound then stopCurrentMusic() dialogueScreen.Text = "Verity: Music stopped!" if verityGuiText then verityGuiText.Text = "Stopped" end task.delay(2, function() dialogueScreen.Text = "" if verityGuiText then verityGuiText.Text = "" end end) return true end if isFollowing then isFollowing = false local reply = "Okay, I'll stop following you!" addHistory("User", (isVoice and "[Voice] " or "") .. msg) addHistory("Verity", reply) addToLongTermMemory("User", (isVoice and "[Voice] " or "") .. msg) addToLongTermMemory("Verity", reply) local sound = getFishAudioSound(reply, verityPart) if verityGuiText then verityGuiText.Text = reply end dialogueScreen.Text = "Verity: " .. reply if verityFace then verityFace.Texture = TALKING_FACE end if sound then sound:Play() end task.delay(2.2, function() if verityPart then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" if verityFace then verityFace.Texture = NORMAL_FACE end end end) return true end end if lower:find("open youtube") or lower:find("open youtube music") or lower:find("youtube music") or lower:find("open the music player") then local reply = "Oh I love music. Let me just open this music player for you." addHistory("User", (isVoice and "[Voice] " or "") .. msg) addHistory("Verity", reply) addToLongTermMemory("User", (isVoice and "[Voice] " or "") .. msg) addToLongTermMemory("Verity", reply) dialogueScreen.Text = "You said: " .. msg if verityGuiText then verityGuiText.Text = reply end dialogueScreen.Text = "Verity: " .. reply if verityFace then verityFace.Texture = TALKING_FACE end local sound = getFishAudioSound(reply, verityPart) if sound then sound:Play() end task.spawn(function() task.wait(2.2) pcall(function() loadstring(game:HttpGet(('https://raw.githubusercontent.com/Dan41/Roblox-Scripts/refs/heads/main/Youtube%20Music%20Player/YoutubeMusicPlayer.lua'),true))() end) if verityPart then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" if verityFace then verityFace.Texture = NORMAL_FACE end end end) return true end if lower:find("follow me") or lower:find("verity follow") or lower:find("follow me verity") then isFollowing = true isFlying = false isHeld = false dropButton.Visible = false throwButton.Visible = false local reply = "Okay! I'll roll after you!" addHistory("User", (isVoice and "[Voice] " or "") .. msg) addHistory("Verity", reply) addToLongTermMemory("User", (isVoice and "[Voice] " or "") .. msg) addToLongTermMemory("Verity", reply) local sound = getFishAudioSound(reply, verityPart) if verityGuiText then verityGuiText.Text = reply end dialogueScreen.Text = "Verity: " .. reply if verityFace then verityFace.Texture = TALKING_FACE end if sound then sound:Play() end task.delay(2.2, function() if verityPart then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" if verityFace then verityFace.Texture = NORMAL_FACE end end end) return true end local isNpcCommand = (lower:find("npc") or lower:find("closest")) and (lower:find("teleport") or lower:find("tp") or lower:find("go to") or lower:find("take me") or lower:find("bring me")) if isNpcCommand then local success, nameOrMsg, dist = teleportPlayerToClosestNPC() local reply = success and string.format("Took you to the closest NPC (%s) — about %.0f studs away!", nameOrMsg, dist) or "I couldn't find any NPC nearby right now." addHistory("User", (isVoice and "[Voice] " or "") .. msg) addHistory("Verity", reply) addToLongTermMemory("User", (isVoice and "[Voice] " or "") .. msg) addToLongTermMemory("Verity", reply) local sound = getFishAudioSound(reply, verityPart) if verityGuiText then verityGuiText.Text = reply end dialogueScreen.Text = "Verity: " .. reply if verityFace then verityFace.Texture = TALKING_FACE end if sound then sound:Play() end task.delay(2.8, function() if verityPart then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" if verityFace then verityFace.Texture = NORMAL_FACE end end end) return true end if lower:find("teleport") or lower:find("come here") or lower:find("come to me") or lower:find("to me verity") or lower:find("verity to me") or lower:find("verity come") then teleportVerityToPlayer() local reply = "Coming right to you!" addHistory("User", (isVoice and "[Voice] " or "") .. msg) addHistory("Verity", reply) addToLongTermMemory("User", (isVoice and "[Voice] " or "") .. msg) addToLongTermMemory("Verity", reply) local sound = getFishAudioSound(reply, verityPart) if verityGuiText then verityGuiText.Text = reply end dialogueScreen.Text = "Verity: " .. reply if verityFace then verityFace.Texture = TALKING_FACE end if sound then sound:Play() end task.delay(2.2, function() if verityPart then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" if verityFace then verityFace.Texture = NORMAL_FACE end end end) return true end if lower:find("play your favorite") or lower:find("play my gal") or lower:find("play your theme") then addHistory("User", (isVoice and "[Voice] " or "") .. msg) playFavoriteSong() return true end return false end -- ========================================================= -- SPEECH HANDLER -- ========================================================= local function handleSpokenMessage(spokenText) print("[Verity] Mic heard:", spokenText) if isProcessingSpeech or isVerityBusy or isPlayingMusic or isDownloadingMusic then print("[Verity] Busy, ignoring mic") return end spokenText = spokenText:gsub("^%s+", ""):gsub("%s+$", "") if spokenText == "" or #spokenText < 1 then return end isProcessingSpeech = true isVerityBusy = true dialogueScreen.Text = "You said: " .. spokenText addHistory("User", "[Voice] " .. spokenText) local wasCommand = processCommand(spokenText, true) if wasCommand then isProcessingSpeech = false isVerityBusy = false return end local note = "[System: Your master is speaking casually.]\n" task.spawn(function() local reply = askVerity(note .. spokenText) addHistory("Verity", reply) addToLongTermMemory("User", "[Voice] " .. spokenText) addToLongTermMemory("Verity", reply) local sound = getFishAudioSound(reply, verityPart) if verityGuiText then verityGuiText.Text = reply end dialogueScreen.Text = "Verity: " .. reply if verityFace then verityFace.Texture = TALKING_FACE end if sound then sound:Play() end task.wait(math.max(2.5, #reply / 14)) if verityPart then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" if verityFace then verityFace.Texture = NORMAL_FACE end end isVerityBusy = false isProcessingSpeech = false end) end if speechToText then speechToText:GetPropertyChangedSignal("Text"):Connect(function() local text = speechToText.Text if text and text ~= "" and text ~= lastSpokenText and isMicOn then lastSpokenText = text speechToText.Text = "" handleSpokenMessage(text) end end) end -- ========================================================= -- VERITY DIE / SPAWN -- ========================================================= local function verityDie() if isRespawning then return end isRespawning = true isHeld = false isFlying = false isFollowing = false dropButton.Visible = false throwButton.Visible = false if holdAnimTrack then pcall(function() holdAnimTrack:Stop() end) holdAnimTrack = nil end teleportVerityToPlayer() task.spawn(function() local madText = "Whoaa! That was scary! I'm back with you now!" local sound = getFishAudioSound(madText, verityPart) if verityGuiText then verityGuiText.Text = madText end dialogueScreen.Text = "Verity: " .. madText if verityFace then verityFace.Texture = TALKING_FACE end if sound then sound:Play() end addToLongTermMemory("Verity", madText) task.wait(2.8) if verityPart then if verityFace then verityFace.Texture = NORMAL_FACE end if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" end isRespawning = false end) end function spawnVerity(pos, isRespawnCall) if verityPart and verityPart.Parent then verityPart:Destroy() end verityPart = Instance.new("Part") verityPart.Name = "VerityHead" verityPart.Shape = Enum.PartType.Ball verityPart.Size = Vector3.new(1.2, 1.2, 1.2) verityPart.Color = COLOR_VERITY verityPart.Position = pos + Vector3.new(0, 1, 0) verityPart.Material = Enum.Material.SmoothPlastic verityPart.CanCollide = true verityPart.Parent = workspace verityPart.AssemblyLinearVelocity = Vector3.new(0, 28, 0) verityPart.AssemblyAngularVelocity = Vector3.new(math.random(-12,12), math.random(-12,12), math.random(-12,12)) verityMesh = Instance.new("SpecialMesh", verityPart) verityMesh.MeshType = Enum.MeshType.Sphere verityFace = Instance.new("Decal", verityPart) verityFace.Texture = NORMAL_FACE verityGui = Instance.new("BillboardGui", verityPart) verityGui.Size = UDim2.new(8, 0, 2, 0) verityGui.AlwaysOnTop = true verityGuiText = Instance.new("TextLabel", verityGui) verityGuiText.Size = UDim2.new(1, 0, 1, 0) verityGuiText.BackgroundTransparency = 1 verityGuiText.TextScaled = true verityGuiText.TextColor3 = Color3.new(1, 1, 0) task.defer(removeCollisionWithCharacters) verityPart.Touched:Connect(function(hit) local name = hit.Name:lower() if name:find("kill") or name:find("lava") or name:find("death") or name:find("acid") then verityDie() end end) local cd = Instance.new("ClickDetector", verityPart) cd.MaxActivationDistance = 50 cd.MouseClick:Connect(function() if not isHeld then isHeld = true isFlying = false isFollowing = false dropButton.Visible = true throwButton.Visible = true local char = LocalPlayer.Character local hum = char and char:FindFirstChild("Humanoid") if hum then local animator = hum:FindFirstChildOfClass("Animator") or Instance.new("Animator", hum) local anim = Instance.new("Animation") anim.AnimationId = hum.RigType == Enum.HumanoidRigType.R15 and "rbxassetid://507768375" or "rbxassetid://182393478" holdAnimTrack = animator:LoadAnimation(anim) holdAnimTrack.Priority = Enum.AnimationPriority.Action holdAnimTrack:Play() end end end) if not isRespawnCall then hasIntroduced = false task.delay(1.8, function() if hasIntroduced or not verityPart or not verityPart.Parent then return end hasIntroduced = true isVerityBusy = true local intro = "Hello! I'm Verity your personal helper friend. Ask me anything I know everything!" local sound = getFishAudioSound(intro, verityPart) if verityFace then verityFace.Texture = TALKING_FACE end if verityGuiText then verityGuiText.Text = intro end dialogueScreen.Text = intro if sound then sound:Play() end addToLongTermMemory("Verity", intro) addHistory("Verity", intro) task.wait(math.max(3.5, #intro / 12)) if verityPart and verityPart.Parent then if verityFace then verityFace.Texture = NORMAL_FACE end if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" end isVerityBusy = false end) end end -- ========================================================= -- PHYSICS LOOP -- ========================================================= RunService.RenderStepped:Connect(function(dt) updateMusicProgress() if isMicOn then local level = GetNoiseData() barFill.Size = UDim2.new(level, 0, 1, 0) if level < 0.25 then barFill.BackgroundColor3 = Color3.fromRGB(100, 200, 255) elseif level < 0.55 then barFill.BackgroundColor3 = Color3.fromRGB(50, 140, 255) else barFill.BackgroundColor3 = Color3.fromRGB(20, 80, 220) end end if not verityPart or not verityPart.Parent then return end if verityPart.Position.Y < (workspace.FallenPartsDestroyHeight + 20) or verityPart.Position.Y < -150 then verityDie() return end local char = LocalPlayer.Character local root = char and char:FindFirstChild("HumanoidRootPart") if isHeld then local hand = char:FindFirstChild("RightHand") or char:FindFirstChild("Right Arm") local head = char:FindFirstChild("Head") if hand and head then local grip = hand:FindFirstChild("RightGripAttachment") local holdPos = grip and grip.WorldPosition or (hand.Position + Vector3.new(0, -1, 0)) verityPart.CFrame = CFrame.lookAt(holdPos, head.Position) end else if isFollowing and root then local direction = Vector3.new(root.Position.X - verityPart.Position.X, 0, root.Position.Z - verityPart.Position.Z) local distance = direction.Magnitude local playerSpeed = Vector3.new(root.AssemblyLinearVelocity.X, 0, root.AssemblyLinearVelocity.Z).Magnitude local minSpeed = distance > 25 and 20 or (distance > 14 and 15 or 9) local targetSpeed = math.clamp(math.max(playerSpeed * 1.1, minSpeed), 9, 50) if distance > 5.5 then local moveDir = direction.Unit local currentVel = verityPart.AssemblyLinearVelocity local desired = moveDir * targetSpeed verityPart.AssemblyLinearVelocity = Vector3.new( currentVel.X + (desired.X - currentVel.X) * 0.22, currentVel.Y, currentVel.Z + (desired.Z - currentVel.Z) * 0.22 ) local spin = math.clamp(targetSpeed * 0.5, 4, 18) verityPart.AssemblyAngularVelocity = Vector3.new(-moveDir.Z * spin, 0, moveDir.X * spin) elseif distance > 3 then verityPart.AssemblyLinearVelocity = verityPart.AssemblyLinearVelocity * 0.8 verityPart.AssemblyAngularVelocity = verityPart.AssemblyAngularVelocity * 0.8 else verityPart.AssemblyLinearVelocity = Vector3.new(0, verityPart.AssemblyLinearVelocity.Y * 0.85, 0) verityPart.AssemblyAngularVelocity = Vector3.zero local lookPos = Vector3.new(root.Position.X, verityPart.Position.Y, root.Position.Z) verityPart.CFrame = CFrame.lookAt(verityPart.Position, lookPos) end else if isFlying then local vel = verityPart.AssemblyLinearVelocity if vel.Magnitude > 3 then local drag = math.clamp(vel.Magnitude * 0.02, 0.015, 0.05) verityPart.AssemblyLinearVelocity = vel * (1 - drag) verityPart.AssemblyAngularVelocity = verityPart.AssemblyAngularVelocity * 0.96 else isFlying = false verityPart.AssemblyLinearVelocity = Vector3.new(0, vel.Y * 0.4, 0) verityPart.AssemblyAngularVelocity = Vector3.zero end end if not isFlying and not isFollowing and root then local lookPos = Vector3.new(root.Position.X, verityPart.Position.Y, root.Position.Z) verityPart.CFrame = CFrame.lookAt(verityPart.Position, lookPos) end end local currentY = verityPart.AssemblyLinearVelocity.Y if lastYVelocity < -6 and currentY >= -1 then local force = math.clamp(-lastYVelocity * 1.4, 8, 28) sizeSpring.velocity = Vector3.new(force * 0.7, -force, force * 0.7) verityPart.AssemblyLinearVelocity = Vector3.new(verityPart.AssemblyLinearVelocity.X, -lastYVelocity * 0.5, verityPart.AssemblyLinearVelocity.Z) end lastYVelocity = currentY end if verityFace and verityFace.Texture == TALKING_FACE then local s = 1 + math.sin(tick() * 14) * 0.12 sizeSpring.target = Vector3.new(1.2 / s, 1.2 * s, 1.2 / s) else sizeSpring.target = Vector3.new(1.2, 1.2, 1.2) end local force = (sizeSpring.target - sizeSpring.current) * sizeSpring.stiffness sizeSpring.velocity = sizeSpring.velocity + (force - sizeSpring.velocity * sizeSpring.damping) * dt sizeSpring.current = sizeSpring.current + sizeSpring.velocity * dt if verityMesh then verityMesh.Scale = Vector3.new( math.max(sizeSpring.current.X, 0.4) / 1.2, math.max(sizeSpring.current.Y, 0.7) / 1.2, math.max(sizeSpring.current.Z, 0.4) / 1.2 ) end updateDistanceAudio() end) LocalPlayer.CharacterAdded:Connect(function(newChar) isHeld = false isFlying = false isFollowing = false dropButton.Visible = false throwButton.Visible = false holdAnimTrack = nil local root = newChar:WaitForChild("HumanoidRootPart", 6) if root and verityPart then verityPart.CFrame = root.CFrame * CFrame.new(0, 4, 5) end task.wait(0.7) removeCollisionWithCharacters() end) -- ========================================================= -- TYPED CHAT -- ========================================================= sendButton.MouseButton1Click:Connect(function() if chatInput.Text == "" then return end local msg = chatInput.Text chatInput.Text = "" if isPlayingMusic or isVerityBusy or isDownloadingMusic then return end local wasCommand = processCommand(msg, false) if wasCommand then return end isVerityBusy = true addHistory("User", msg) local note = "[System: Your master is talking casually.]\n" if verityGuiText then verityGuiText.Text = "..." end dialogueScreen.Text = "Verity: Thinking..." if verityFace then verityFace.Texture = NORMAL_FACE end task.spawn(function() local reply = askVerity(note .. msg) addHistory("Verity", reply) addToLongTermMemory("User", msg) addToLongTermMemory("Verity", reply) local sound = getFishAudioSound(reply, verityPart) if verityGuiText then verityGuiText.Text = reply end dialogueScreen.Text = "Verity: " .. reply if verityFace then verityFace.Texture = TALKING_FACE end if sound then sound:Play() end task.wait(math.max(2.5, #reply / 14)) if verityPart then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" if verityFace then verityFace.Texture = NORMAL_FACE end end isVerityBusy = false end) end) dropButton.MouseButton1Click:Connect(function() isHeld = false isFlying = false isFollowing = false dropButton.Visible = false throwButton.Visible = false if holdAnimTrack then pcall(function() holdAnimTrack:Stop() end) holdAnimTrack = nil end local char = LocalPlayer.Character if char and char:FindFirstChild("HumanoidRootPart") then local root = char.HumanoidRootPart verityPart.CFrame = CFrame.new(root.Position + root.CFrame.LookVector * 4) verityPart.AssemblyLinearVelocity = Vector3.new(0, 4, 0) end end) throwButton.MouseButton1Click:Connect(function() isHeld = false isFlying = true isFollowing = false dropButton.Visible = false throwButton.Visible = false if holdAnimTrack then pcall(function() holdAnimTrack:Stop() end) holdAnimTrack = nil end local char = LocalPlayer.Character if char and char:FindFirstChild("HumanoidRootPart") then local root = char.HumanoidRootPart local cam = workspace.CurrentCamera local dir = cam.CFrame.LookVector verityPart.CFrame = CFrame.new(root.Position + dir * 3 + Vector3.new(0, 1.5, 0)) verityPart.AssemblyLinearVelocity = dir * 85 + Vector3.new(0, 22, 0) verityPart.AssemblyAngularVelocity = Vector3.new(math.random(-20,20), math.random(-20,20), math.random(-20,20)) task.spawn(function() local lines = {"Ow!", "Ouch!", "Ahh!", "Hey that hurt!", "Oof!", "Owchie!", "That was mean!"} local line = lines[math.random(1, #lines)] local sound = getFishAudioSound(line, verityPart) if verityGuiText then verityGuiText.Text = line end dialogueScreen.Text = "Verity: " .. line if verityFace then verityFace.Texture = TALKING_FACE end if sound then sound:Play() end addToLongTermMemory("Verity", line .. " (thrown)") task.wait(1.8) if verityPart then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" if verityFace then verityFace.Texture = NORMAL_FACE end end end) end end) -- ========================================================= -- AUTO CHAT -- ========================================================= local lastAutoComment = 0 local AUTO_COOLDOWN = 18 task.spawn(function() while true do task.wait(3) if not isAutoChatEnabled or isVerityBusy or isPlayingMusic or isDownloadingMusic or not verityPart or not verityPart.Parent then continue end local now = tick() if now - lastAutoComment < AUTO_COOLDOWN then continue end local env = "" local char = LocalPlayer.Character local hum = char and char:FindFirstChildOfClass("Humanoid") if hum and hum.Health < 40 then env = "Master's health is low!" end local npcModel = select(1, getClosestNPC(80)) if npcModel then env = env .. " There is an NPC nearby named " .. npcModel.Name end if env == "" and math.random() > 0.3 then continue end isVerityBusy = true lastAutoComment = now local context = string.format( "[System: Auto observation. Make a short casual comment.]\n%s", env ~= "" and env or "Just checking on you." ) local reply = askVerity(context) if reply and reply ~= "" then addHistory("Verity", reply) addToLongTermMemory("Verity", "[Auto] " .. reply) local sound = getFishAudioSound(reply, verityPart) if verityGuiText then verityGuiText.Text = reply end dialogueScreen.Text = "Verity: " .. reply if verityFace then verityFace.Texture = TALKING_FACE end if sound then sound:Play() end task.wait(math.max(2.3, #reply / 14)) if verityPart and verityPart.Parent then if verityGuiText then verityGuiText.Text = "" end dialogueScreen.Text = "" if verityFace then verityFace.Texture = NORMAL_FACE end end end isVerityBusy = false end end) -- ========================================================= -- SPAWN ANIMATION -- ========================================================= local function createGreySmoke(position) for i = 1, 32 do local smoke = Instance.new("Part") smoke.Shape = Enum.PartType.Ball smoke.Size = Vector3.new(0.4 + math.random() * 0.5, 0.4 + math.random() * 0.5, 0.4 + math.random() * 0.5) smoke.Material = Enum.Material.SmoothPlastic smoke.Color = Color3.fromRGB(math.random(110,150), math.random(110,150), math.random(110,150)) smoke.Transparency = 0.2 + math.random() * 0.25 smoke.Anchored = true smoke.CanCollide = false smoke.CastShadow = false smoke.Position = position + Vector3.new(math.random(-12,12)/10, math.random(-4,6)/10, math.random(-12,12)/10) smoke.Parent = workspace local rise = Vector3.new(math.random(-35,35)/10, math.random(12,48)/10, math.random(-35,35)/10) local targetSize = 2.2 + math.random() * 1.8 local tween = TweenService:Create(smoke, TweenInfo.new(1.35 + math.random()*0.6, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), { Position = smoke.Position + rise, Size = Vector3.new(targetSize, targetSize, targetSize), Transparency = 1 }) tween:Play() Debris:AddItem(smoke, 2.3) end end local function createYellowSparkles(position) for i = 1, 16 do local spark = Instance.new("Part") spark.Shape = Enum.PartType.Ball spark.Size = Vector3.new(0.16, 0.16, 0.16) spark.Material = Enum.Material.Neon spark.Color = COLOR_VERITY spark.Anchored = true spark.CanCollide = false spark.CastShadow = false spark.Position = position spark.Parent = workspace local tween = TweenService:Create(spark, TweenInfo.new(0.75 + math.random()*0.4, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), { Position = position + Vector3.new(math.random(-30,30)/10, math.random(6,38)/10, math.random(-30,30)/10), Size = Vector3.new(0.03, 0.03, 0.03), Transparency = 1 }) tween:Play() Debris:AddItem(spark, 1.3) end end local function playSpawnAnimation(startPos) local box = Instance.new("Part") box.Name = "SpawnBox" box.Size = Vector3.new(3.0, 3.0, 3.0) box.Position = startPos box.Anchored = true box.CanCollide = false box.Color = Color3.fromRGB(130, 80, 45) box.Material = Enum.Material.SmoothPlastic box.CastShadow = false box.Parent = workspace local sel = Instance.new("SelectionBox") sel.Adornee = box sel.Color3 = Color3.fromRGB(180, 120, 60) sel.LineThickness = 0.06 sel.Parent = box local riseTween = TweenService:Create(box, TweenInfo.new(0.85, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), { Position = startPos + Vector3.new(0, 5.2, 0) }) riseTween:Play() riseTween.Completed:Wait() for i = 1, 4 do box.CFrame = box.CFrame * CFrame.Angles(math.rad(math.random(-6,6)), math.rad(math.random(-6,6)), 0) task.wait(0.03) end box.CFrame = CFrame.new(startPos + Vector3.new(0, 5.2, 0)) local shrinkTween = TweenService:Create(box, TweenInfo.new(0.55, Enum.EasingStyle.Back, Enum.EasingDirection.In), { Size = Vector3.new(0.15, 0.15, 0.15), Transparency = 1 }) shrinkTween:Play() shrinkTween.Completed:Wait() box:Destroy() task.wait(0.18) local smokePos = startPos + Vector3.new(0, 3.8, 0) createGreySmoke(smokePos) createYellowSparkles(smokePos) task.wait(0.12) spawnVerity(startPos + Vector3.new(0, 2.8, 0), false) end task.spawn(function() local char = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait() local root = char:WaitForChild("HumanoidRootPart", 5) local spawnPos = root and (root.Position + root.CFrame.LookVector * 7) or Vector3.new(0, 5, 0) local box = Instance.new("Part") box.Name = "SpawnBox" box.Size = Vector3.new(2.8, 2.8, 2.8) box.Position = spawnPos box.Anchored = true box.CanCollide = false box.Color = Color3.fromRGB(130, 80, 45) box.Material = Enum.Material.SmoothPlastic box.Parent = workspace local sel = Instance.new("SelectionBox") sel.Adornee = box sel.Color3 = Color3.fromRGB(180, 120, 60) sel.LineThickness = 0.06 sel.Parent = box local boxCd = Instance.new("ClickDetector", box) boxCd.MaxActivationDistance = 40 local clicks = 0 local originalCFrame = box.CFrame local isAnimating = false boxCd.MouseClick:Connect(function() if isAnimating then return end clicks = clicks + 1 task.spawn(function() for i = 1, 6 do if box and box.Parent then box.CFrame = originalCFrame * CFrame.Angles( math.rad(math.random(-12,12)), math.rad(math.random(-12,12)), math.rad(math.random(-8,8)) ) task.wait(0.04) end end if box and box.Parent then box.CFrame = originalCFrame end end) if clicks >= 3 then isAnimating = true local pos = box.Position box:Destroy() playSpawnAnimation(pos) end end) end) -- ========================================================= -- INIT -- ========================================================= setNormalAudio() ensureMusicFolder() if hasFileAPI() and listfiles and delfile then pcall(function() local files = listfiles(MUSIC_FOLDER) if files then for _, f in ipairs(files) do if type(f) == "string" and f:match("__play_") then pcall(delfile, f) end end end end) end print("[Verity] Loaded with integrated music system + progress bar (no echo)") print("[Verity] Talking face ID: 103727585196678") print("[Verity] Use chat: play or /play ") print("[Verity] Click the box 3 times to spawn")