local voicelines = { [1] = { 123044303994375, 103660746061428, 75637648039086, 5030402048, 86837306997861, 96281103613406, 137581198061053, 97852528632885, 5161592186, 99927181905461, 94960112472516, 4541552530, 138155938349025, 2164397857, 77680306214562, 125454319097196, 139785351379081, 119866685732193, 6364600789, 4541601937, 7226610682, 135074773934459, 114000468625580, 119669644558502, 4541496591, 77927942306834, 7436555614, 100053426740689, 73944013855086, 111134077549844, 8266908202, 88558209523087, 77767534864229, 100718900484328, 86489612055236, 140177918664226, 89947470135373, 138023320028337, 7518827825, 107811801422160, 111185293097461, 74224041251020, 133871445663152, 107462093686133, 89772394068591, 82706203808655, 83348169518954, 90997053045711, 78096726451207, 136349473943981, 134229432519727, 140644686986145, 75536411243388, 89089261050741, 86394425280837, 101942393815597, 84917813742365, 109523676339672, 100785284742630, 120738866199180, 127682283769953, 105656929862560, 82461785419863, 121655250859854, 78903997608315, 103174106803434, 134097384411270, 97509020628298, 7518835656, 134937624513424, 137363192765480, 125746048332941, 127380548842621, 128536736641243, 81988139281220, 111813337356720, 134124154776208, 130400014876558, 115350222916022, 128469629950144, 87453017467147, 84881583814092, 83719896470978, 98688401406115, 83698740666045, 113048198226469, 114088246078285, 100340156582123, 101816267586417, 85365894642945, 120224963718630, 127781343273877, 98495875536738, 107819330848898, 134653783511274, 77285387413057, 91895029907428, 5359431243, 72414792787245, 92279199079271, 84632739448429, 95831042912410, 140644831633779, 92037028831221, 115516809640212, 132686709305301, 90151067916460, 120987979668202, 117245798021315, 95376108276083, 89678520529165, 5717121527, 104325116068612, 108706289463478, 74027948052683, 117333274135220, 7078730266, 122586997527353, 80383471346647, 13502750239, 128301429841017, 120007408401235, 132707208976018, 129099343557564, 140201753911558, 90354737662165, 136514507117808, 113604801712666, 111583187408971, 104392572604782, 84931461699163, 135940592018966, 89648856262009, 123077176424112, 138864598498483, 111677597842516, 80301627508319, 92888520831475, 135455822510958, 4269343309, 86771275626153, 18960307174, 103313929612435, 84512277901997, 136515209354869, 95072412283035, 75099750017962, 7102441747, 74446091290636, 93857490751151, 140505698910456, 73151937286069, 117689483112264, 112857810922097, 79332954343290, 103182202071549, 121809529868087, 8830417389, 124288658658869, 122060876723823, 97541058657879, 109603358638247, 102125069984975, 134283353678806, 131140990880922, 117236105724823, 116614571801498, 137884010024670, 9118907001, 101565269491832, 85843840195489, 132711750902093, 124866950774339, 102560602322001, 110771398988100, 86036858040298, 138822171314257, 91029029275852, 121468353358396, 116195744920617, 136532027751110, 6400547643, 70979345372029, 75005076882649, 89636569052293, 138442043819459, 130953728323065, 76700051050162, 117593323315250, 140037223576002, 113027067329756, 77370447654653, 118214676544833, 140384727798439, 134549360210972, 132485278597776, 125169624790105, 116106179787633, 104991057651871, 104221287036914, 7173976933, 7169485926, 108458794103088, 128217175445044, 98065299568261, 72692630081496, 88751021428882, 123556631405308, 135909181856526, 131475073519274, 130487946468477, 129672214850442, 127228515866792, 126683068752302, 119467299888806, 117325264323989, 106044493989182, 95611319293585, 94147072524450, 93787950025550, 85099269013874, 85510602512034, 75130373593960, 73284353028765, 9117803265, 9117802186, 9113461595, 9066422312, 8751354974, 7662156159, 7662145278, 7662129214, 7662116657, 6984479449, 6984423651, 4980436517, 1253565304, 1253558886, 138535601469792, 9125773982, 125853087610330, 104347159363539, 96719824081387, 79210276414151, 3892151882, 7105187524, 104226481380868, 86926175961875, 99248100907398, 111373247510728, 137812336859925, 72875981721445, 117992684269470, 82241925071719, 122771968483267, 121521552258987, 126296283190978, 129503172509025, 92338441194085, 81588784147895, 132603075666016, 116245229309693, 106296775532751, 72285865814647, 75690425331627, 109205203550230, 83321762959042, 5256600840, 6860725411, 131349769139285, 73809996990793, 8742003414, 100670471448441, 78311278956073, 107741584211234, 108201876079710, 116316828209167, 92058045131140, 73550334887374, 93581420805853, 71652979013382, 9117800464, 98774782275896, 81994115419537, 109969981277507, 105113656480314, 72839390391168, 7159310972, 71198952735275, 97866017637646, 118926509382938, 90626684549819, 75313342766037, 139441486682031, 75036337376608, 9117801185, 123979217071359, 119665126324216, 116810636115696, 110986192072697, 131073013941233, 124663801420429, 131435365612251, 113214756266889, 73099897790517, 126755337402751, 6984514157, 107667766078851, 95500081888104, 71074580551637, 85777622219760, 87587071290310, 131315418528721, 85626179321332, 133895736596002, 115568873580262, 76744769738457, 115232492430878 }, [2] = { 77503682299807, 88506904433512, 135651685303108, 5887507874, 89738815265557, 103552223389683, 183345423, 5291641717, 17712048342, 114739399228816, 124085568487204, 70545394897779, 81473153453639, 124102449219812, 117304386224395, 134631462190753, 133212103539028, 123572846158655, 88631209504508, 86766344642064, 75199053916603, 116565600001923, 87792884329852, 137378206255510 }, [3] = { 129187403689496, 126619913329099, 4980304037, 135881090369317, 78523844245618, 9058909979, 97480286525719, 92241766174214, 104461187583348, 1080610583, 565424701, 112398446636056, 3604140002, 1106906657, 571884894, 1080625252, 96271190588167, 17638604308, 18900008907, 81602283697675, 90700989840687, 75201111270943, 100494222092218, 138653824465794, 116569075451653, 129016542446095, 107081526006526, 7745218668, 120684568421123, 112618609792970, 76981902327303, 89566790255807 }, [4] = { 7393525156, 679847985, 1000204726, 73880845386129, 126986741585934, 7085409495, 131558826975154, 81218800788892, 8974931344, 95457517353904, 97586771453333, 116978677797205, 114834244992089, 111204965045440, 116890211384648, 130963551021153, 100229277884126, 139053006613829, 105808563439062, 88558077689131, 110475244339697, 5685399745, 5223746841, 103139690245935, 138796141112694, 128213715101985, 93398055562825, 111507391511100, 105720610295075, 128203559567945, 17571063959, 78876396429378, 130723519809726 } } local players = game:GetService("Players") local workspace = game:GetService("Workspace") local me = players.LocalPlayer local playing = {} local data = {} local timers = {} local activeIcons = {} local activeTimers = {} local cd = { [1] = 3, [2] = 10, [3] = 10, [4] = 1.5 } local chances = { [1] = 50, [4] = 70 } local ranges = { far = 200, close = 50 } local options = { hearMe = true, loudness = 1.0 } local function createBillboardIcon(character) if not character then return nil end local attachPart = character:FindFirstChild("Head") if not attachPart then attachPart = character:FindFirstChild("UpperTorso") end if not attachPart then attachPart = character:FindFirstChild("Torso") end if not attachPart then attachPart = character:FindFirstChild("HumanoidRootPart") end if not attachPart then return nil end local oldIcon = character:FindFirstChild("VoiceBillboard") if oldIcon then oldIcon:Destroy() end local billboard = Instance.new("BillboardGui") billboard.Name = "VoiceBillboard" billboard.Adornee = attachPart billboard.Size = UDim2.new(0, 50, 0, 50) billboard.StudsOffset = Vector3.new(0, 2.5, 0) billboard.AlwaysOnTop = false billboard.MaxDistance = 0 local imageLabel = Instance.new("ImageLabel") imageLabel.Size = UDim2.new(1, 0, 1, 0) imageLabel.BackgroundTransparency = 1 imageLabel.Image = "rbxassetid://16969537160" imageLabel.ScaleType = Enum.ScaleType.Fit imageLabel.Parent = billboard billboard.Parent = character billboard.Enabled = false return billboard end local function showIcon(player, duration) if not player or not player.Character then return end local character = player.Character local billboard = character:FindFirstChild("VoiceBillboard") if not billboard then billboard = createBillboardIcon(character) end if billboard then local attachPart = character:FindFirstChild("Head") if not attachPart then attachPart = character:FindFirstChild("UpperTorso") or character:FindFirstChild("Torso") or character:FindFirstChild("HumanoidRootPart") end if attachPart then billboard.Adornee = attachPart end if activeTimers[player] then task.cancel(activeTimers[player]) end billboard.Enabled = true activeTimers[player] = task.delay(duration, function() if billboard and billboard.Parent then billboard.Enabled = false end activeTimers[player] = nil end) end end local function getSoundDuration(id, callback) local sound = Instance.new("Sound") sound.SoundId = "rbxassetid://" .. tostring(id) sound.Volume = 0 local anchor = Instance.new("Part") anchor.Size = Vector3.new(0.1, 0.1, 0.1) anchor.Transparency = 1 anchor.CanCollide = false anchor.Anchored = true anchor.Position = Vector3.new(0, 0, 0) anchor.Parent = workspace sound.Parent = anchor local connection connection = sound.Played:Connect(function() local duration = sound.TimeLength if duration > 0 then callback(duration) else callback(2.5) end sound:Stop() anchor:Destroy() connection:Disconnect() end) task.delay(1, function() if sound and sound.Parent then callback(2.5) sound:Stop() anchor:Destroy() if connection then connection:Disconnect() end end end) sound:Play() end local function setupIconOnCharacter(player) if player.Character then createBillboardIcon(player.Character) end player.CharacterAdded:Connect(function(character) task.wait(0.2) createBillboardIcon(character) end) end local function grab(t) if type(t) ~= "table" or #t == 0 then return nil end return t[math.random(1, #t)] end local function allowed(p, kind) local now = os.clock() if not timers[p] then timers[p] = {} end local waitTime = cd[kind] or 3 local lastTime = timers[p][kind] if lastTime and (now - lastTime) < waitTime then return false end return true end local function mark(p, kind) local now = os.clock() if not timers[p] then timers[p] = {} end timers[p][kind] = now end local function howFar(p1, p2) if not p1.Character or not p2.Character then return 99999 end local r1 = p1.Character:FindFirstChild("HumanoidRootPart") local r2 = p2.Character:FindFirstChild("HumanoidRootPart") if not r1 or not r2 then return 99999 end return (r2.Position - r1.Position).Magnitude end local function closeEnough(p, r) if p == me and options.hearMe then return true end local d = howFar(me, p) return d <= r end local function getPlayerPosition(p) if not p or not p.Character then return nil end local root = p.Character:FindFirstChild("HumanoidRootPart") if root then return root.Position end local torso = p.Character:FindFirstChild("UpperTorso") or p.Character:FindFirstChild("Torso") if torso then return torso.Position end local head = p.Character:FindFirstChild("Head") if head then return head.Position end return nil end local function playSound(id, player, kind) local pos = getPlayerPosition(player) if not pos then return false end local distance = howFar(me, player) if kind ~= 4 then if player ~= me and distance > ranges.far then return false end end getSoundDuration(id, function(duration) showIcon(player, duration) end) local sound = Instance.new("Sound") sound.SoundId = "rbxassetid://" .. tostring(id) sound.Volume = options.loudness local anchor = Instance.new("Part") anchor.Size = Vector3.new(0.1, 0.1, 0.1) anchor.Transparency = 1 anchor.CanCollide = false anchor.Anchored = true anchor.Position = pos anchor.Parent = workspace sound.Parent = anchor if player ~= me then if distance <= 10 then sound.Volume = 1.0 * options.loudness sound.RollOffMode = Enum.RollOffMode.Linear sound.RollOffMinDistance = 5 sound.RollOffMaxDistance = 100 elseif distance <= 30 then sound.Volume = 0.8 * options.loudness sound.RollOffMode = Enum.RollOffMode.Linear sound.RollOffMinDistance = 10 sound.RollOffMaxDistance = 150 elseif distance <= 60 then sound.Volume = 0.6 * options.loudness sound.RollOffMode = Enum.RollOffMode.Linear sound.RollOffMinDistance = 15 sound.RollOffMaxDistance = 200 else sound.Volume = 0.4 * options.loudness sound.RollOffMode = Enum.RollOffMode.Linear sound.RollOffMinDistance = 20 sound.RollOffMaxDistance = 300 end else sound.RollOffMode = Enum.RollOffMode.Linear sound.Volume = 1.0 * options.loudness end local soundData = { sound = sound, anchor = anchor, player = player } local idx = #playing + 1 playing[idx] = soundData sound.Ended:Connect(function() if anchor and anchor.Parent then anchor:Destroy() end playing[idx] = nil end) task.delay(15, function() if playing[idx] then if sound then sound:Stop() end if anchor and anchor.Parent then anchor:Destroy() end playing[idx] = nil end end) sound:Play() return true end local function moveSounds() for _, info in pairs(playing) do if info and info.player and info.anchor then if not info.player.Character then if info.sound then info.sound:Stop() end if info.anchor.Parent then info.anchor:Destroy() end else local newPos = getPlayerPosition(info.player) if newPos and info.anchor.Parent then info.anchor.Position = newPos end end end end end coroutine.wrap(function() while true do moveSounds() task.wait(0.05) end end)() local function talkBack(trigger) if not trigger or trigger == me then return end if not closeEnough(trigger, ranges.close) then return end local canTalk = {} for _, p in ipairs(players:GetPlayers()) do if p ~= trigger and p ~= me then if closeEnough(p, ranges.close) and allowed(p, 4) then table.insert(canTalk, p) end end end for _, talker in ipairs(canTalk) do if math.random(1, 100) <= chances[4] then local delay = math.random(1, math.max(1, #canTalk)) * 0.15 task.delay(delay, function() if allowed(talker, 4) then local id = grab(voicelines[4]) if id then playSound(id, talker, 4) mark(talker, 4) end end end) end end end local function trackPlayer(player) data[player] = { hp = 100, lastHp = 100 } setupIconOnCharacter(player) local function onCharacterAdded(character) task.wait(0.5) local humanoid = character:FindFirstChild("Humanoid") if not humanoid then return end data[player].hp = humanoid.Health data[player].lastHp = humanoid.Health local function onHealthChanged(newHealth) local oldHealth = data[player].lastHp if newHealth < oldHealth then if newHealth > 0 then if allowed(player, 2) then local id = grab(voicelines[2]) if id then playSound(id, player, 2) mark(player, 2) task.wait(0.2) talkBack(player) end end else if allowed(player, 3) then local id = grab(voicelines[3]) if id then playSound(id, player, 3) mark(player, 3) task.wait(0.3) talkBack(player) end end end end data[player].lastHp = newHealth data[player].hp = newHealth end humanoid.HealthChanged:Connect(onHealthChanged) humanoid.Died:Connect(function() if allowed(player, 3) then local id = grab(voicelines[3]) if id then playSound(id, player, 3) mark(player, 3) task.wait(0.3) talkBack(player) end end data[player].hp = 0 end) end if player.Character then onCharacterAdded(player.Character) end player.CharacterAdded:Connect(onCharacterAdded) coroutine.wrap(function() while player.Parent do task.wait(math.random(20, 45)) if math.random(1, 100) <= chances[1] then if allowed(player, 1) then local id = grab(voicelines[1]) if id then playSound(id, player, 1) mark(player, 1) task.wait(0.3) talkBack(player) end end end end end)() end for _, player in ipairs(players:GetPlayers()) do task.spawn(function() trackPlayer(player) end) end players.PlayerAdded:Connect(function(player) task.spawn(function() trackPlayer(player) end) end) players.PlayerRemoving:Connect(function(player) data[player] = nil timers[player] = nil if activeTimers[player] then task.cancel(activeTimers[player]) activeTimers[player] = nil end if player.Character then local icon = player.Character:FindFirstChild("VoiceBillboard") if icon then icon:Destroy() end end for id, info in pairs(playing) do if info and info.player == player then if info.sound then info.sound:Stop() end if info.anchor and info.anchor.Parent then info.anchor:Destroy() end playing[id] = nil end end end) task.wait(math.random(3, 8)) local firstSound = grab(voicelines[1]) if firstSound then playSound(firstSound, me, 1) end local voice = {} voice.say = function(kind, playerName) local target = playerName and players:FindFirstChild(playerName) or me if not target then return false end local id if kind == 2 then id = grab(voicelines[2]) elseif kind == 3 then id = grab(voicelines[3]) elseif kind == 4 then id = grab(voicelines[4]) else id = grab(voicelines[1]) end if id then return playSound(id, target, kind) end return false end voice.range = function(dist) if type(dist) == "number" and dist > 0 then ranges.far = dist end end voice.talkRange = function(dist) if type(dist) == "number" and dist >= 0 then ranges.close = dist end end voice.volume = function(mult) if type(mult) == "number" and mult > 0 then options.loudness = mult end end voice.shutup = function() for _, info in pairs(playing) do if info and info.sound then info.sound:Stop() end if info and info.anchor and info.anchor.Parent then info.anchor:Destroy() end end playing = {} end return voice