local voicelines = { [1] = { 123044303994375, 103660746061428, 75637648039086, 5030402048, 86837306997861, 96281103613406, 137581198061053, 97852528632885, 5161592186, 99927181905461, 94960112472516, 4541552530, 138155938349025, 2164397857, 77680306214562, 125454319097196, 113361786686535, 139785351379081, 119866685732193, 6364600789, 4541601937, 7226610682, 135074773934459, 114000468625580, 119669644558502, 4541496591, 77927942306834, 7436555614, 100053426740689, 73944013855086, 111134077549844, 96698322761319, 8266908202, 88558209523087, 77767534864229, 100718900484328, 86489612055236, 140177918664226, 89947470135373, 138023320028337, 7518827825, 107811801422160, 111185293097461, 74224041251020, 133871445663152, 107462093686133, 74657172927121, 89772394068591, 82706203808655, 83348169518954, 90997053045711, 78096726451207, 136349473943981, 134229432519727, 140644686986145, 75536411243388, 89089261050741, 86394425280837, 101942393815597, 84917813742365, 109523676339672, 100785284742630, 130976875377436, 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, 117050393188764, 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 }, [2] = { 77503682299807, 88506904433512, 135651685303108, 5887507874, 89738815265557, 103552223389683, 183345423, 5291641717, 17712048342, 114739399228816, 124085568487204, 70545394897779, 81473153453639, 124102449219812 }, [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 }, [4] = { 7393525156, 679847985, 1000204726, 73880845386129, 126986741585934, 7085409495, 131558826975154, 81218800788892, 117050393188764, 8974931344, 95457517353904, 97586771453333, 116978677797205 } } local players = game.Players local workspace = game.Workspace local me = players.LocalPlayer local playing = {} local data = {} local timers = {} local last = {} local cd = { [1] = 3, [2] = 6, [3] = 10, [4] = 2 } local chances = { [1] = 50, [4] = 70 } local ranges = { far = 200, close = 50 } local options = { hearMe = true, loudness = 1.0 } local function grab(t) if #t == 0 then return end return t[math.random(1, #t)] end local function allowed(p, kind) local now = tick() local t = timers[p] if not t then t = {} end local waitTime = cd[kind] or 3 local lastTime = t[kind] if lastTime and (now - lastTime) < waitTime then return false end return true end local function mark(p, kind) local now = tick() 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 where(p) if not p or not p.Character then return nil end local h = p.Character:FindFirstChild("Head") local r = p.Character:FindFirstChild("HumanoidRootPart") if h then return h.Position elseif r then return r.Position end return p.Character:GetPivot().Position end local function play(id, p, kind) local pos = where(p) if not pos then return false end local d = howFar(me, p) if kind ~= 4 then if p == me then else if d > ranges.far then return false end end end local s = Instance.new("Sound") s.SoundId = "rbxassetid://" .. tostring(id) s.Volume = 1.0 * 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 s.Parent = anchor if p ~= me then if d <= 10 then s.Volume = 1.0 * options.loudness s.RollOffMode = Enum.RollOffMode.Linear s.RollOffMinDistance = 5 s.RollOffMaxDistance = 100 elseif d <= 30 then s.Volume = 0.8 * options.loudness s.RollOffMode = Enum.RollOffMode.Linear s.RollOffMinDistance = 10 s.RollOffMaxDistance = 150 elseif d <= 60 then s.Volume = 0.6 * options.loudness s.RollOffMode = Enum.RollOffMode.Linear s.RollOffMinDistance = 15 s.RollOffMaxDistance = 200 else s.Volume = 0.4 * options.loudness s.RollOffMode = Enum.RollOffMode.Linear s.RollOffMinDistance = 20 s.RollOffMaxDistance = 300 end else s.RollOffMode = Enum.RollOffMode.Linear s.Volume = 1.0 * options.loudness end local info = { sound = s, anchor = anchor, player = p, pos = pos, dist = d } local idx = #playing + 1 playing[idx] = info s.Ended:Connect(function() if anchor.Parent then anchor:Destroy() end playing[idx] = nil end) task.delay(15, function() if playing[idx] then s:Stop() if anchor.Parent then anchor:Destroy() end playing[idx] = nil end end) s:Play() last[p] = tick() 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 = where(info.player) if newPos and info.anchor.Parent then info.anchor.Position = newPos info.pos = newPos end end end end end coroutine.wrap(function() while true do moveSounds() 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 if #canTalk == 0 then return end for _, talker in ipairs(canTalk) do if math.random(1, 100) <= chances[4] then wait(math.random(0.2, 1.0)) if allowed(talker, 4) then local id = grab(voicelines[4]) if id then if play(id, talker, 4) then mark(talker, 4) end end end end end end local function track(p) data[p] = { hp = 100, alive = true, lastHp = 100 } local function setup(c) wait(0.5) local h = c:WaitForChild("Humanoid", 5) if not h then return end data[p].hp = h.Health data[p].alive = h.Health > 0 data[p].lastHp = h.Health local function ouch(newHp) local d = data[p] local oldHp = d.lastHp if newHp < oldHp then local damage = oldHp - newHp if newHp > 0 then if allowed(p, 2) then local id = grab(voicelines[2]) if id then if play(id, p, 2) then mark(p, 2) wait(0.3) talkBack(p) end end end elseif newHp <= 0 then if allowed(p, 3) then local id = grab(voicelines[3]) if id then if play(id, p, 3) then mark(p, 3) wait(0.5) talkBack(p) end end end end end d.lastHp = newHp d.hp = newHp d.alive = newHp > 0 end h.HealthChanged:Connect(function(newHp) ouch(newHp) end) h.Died:Connect(function() if allowed(p, 3) then local id = grab(voicelines[3]) if id then if play(id, p, 3) then mark(p, 3) wait(0.5) talkBack(p) end end end data[p].alive = false data[p].hp = 0 end) end if p.Character then setup(p.Character) end p.CharacterAdded:Connect(setup) coroutine.wrap(function() while p.Parent do wait(math.random(20, 45)) if math.random(1, 100) <= chances[1] then if allowed(p, 1) then local id = grab(voicelines[1]) if id then if play(id, p, 1) then mark(p, 1) wait(0.5) talkBack(p) end end end end end end)() end for _, p in ipairs(players:GetPlayers()) do track(p) end players.PlayerAdded:Connect(track) players.PlayerRemoving:Connect(function(p) data[p] = nil timers[p] = nil last[p] = nil for id, info in pairs(playing) do if info.player == p 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) wait(math.random(3, 8)) local first = grab(voicelines[1]) if first then play(first, me, 1) end local voice = {} voice.say = function(kind, name) local p = name and players:FindFirstChild(name) or me if not p 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 play(id, p, 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.sound then info.sound:Stop() end if info.anchor and info.anchor.Parent then info.anchor:Destroy() end end playing = {} end return voice