local function G(G,f,v)return f+(v-f)*math.min(string.len(G)/75.0,1.0)end local function f()local G={}G.data={}local f=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")G.Emptied=f.Event function G.Size(f)return#G.data end function G.Empty(f)return G:Size()<=0 end function G.PopFront(v)table.remove(G.data,1)if G:Empty()then f:Fire()end end function G.Front(f)return G.data[1]end function G.Get(v,f)return G.data[f]end function G.PushBack(v,f)table.insert(G.data,f)end function G.GetData(f)return G.data end return G end local function v()local G={}G.Fifo=f()G.BillboardGui=nil return G end local function e()local G={}G.data={}local f=0 function G.Size(G)return f end function G.Erase(e,v)if G.data[v]then f=f-1 end G.data[v]=nil end function G.Set(z,v,e)G.data[v]=e if e then f=f+1 end end function G.Get(e,f)if not f then return end if not G.data[f]then G.data[f]=v()local e=nil e=G.data[f].Fifo.Emptied:connect(function()e:disconnect()G:Erase(f)end)end return G.data[f]end function G.GetData(f)return G.data end return G end local function z(f,v,e)local z={}function z.ComputeBubbleLifetime(e,f,v)if v then return G(f,8,15)else return G(f,12,20)end end z.Origin=nil z.RenderBubble=nil z.Message=f z.BubbleDieDelay=z:ComputeBubbleLifetime(f,e)z.BubbleColor=v z.IsLocalPlayer=e return z end local function j(G,f,v)local e=z(f,BubbleColor.WHITE,v)if G then e.User=G.Name e.Origin=G.Character end return e end local function r(G,f,v,e)local j=z(f,e,v)j.Origin=G return j end function createChatBubbleMain(G,f)local v=Instance.new("\073\109\097\103\101\076\097\098\101\108")v.Name="\067\104\097\116\066\117\098\098\108\101"v.ScaleType=Enum.ScaleType.Slice v.SliceCenter=f v.Image="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047"..(tostring(G).."\046\112\110\103")v.BackgroundTransparency=1 v.ImageColor3=Color3.fromRGB(0,0,0)v.BorderSizePixel=0 v.Size=UDim2.new(1.0,0,1.0,0)v.Position=UDim2.new(0,0,0,0)return v end function createChatBubbleTail(G,f)local v=Instance.new("\073\109\097\103\101\076\097\098\101\108")v.Name="\067\104\097\116\066\117\098\098\108\101\084\097\105\108"v.Image="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047\117\105\047\100\105\097\108\111\103\095\116\097\105\108\046\112\110\103"v.BackgroundTransparency=1 v.BorderSizePixel=0 v.Position=G v.Size=f v.ImageColor3=Color3.fromRGB(0,0,0)return v end function createChatBubbleWithTail(G,f,v,e)local z=createChatBubbleMain(G,e)local j=createChatBubbleTail(f,v)j.Parent=z return z end function createScaledChatBubbleWithTail(G,f,v,e)local z=createChatBubbleMain(G,e)local j=Instance.new("\070\114\097\109\101")j.Name="\067\104\097\116\066\117\098\098\108\101\084\097\105\108\070\114\097\109\101"j.BackgroundTransparency=1 j.SizeConstraint=Enum.SizeConstraint.RelativeXX j.BackgroundColor3=Color3.fromRGB(0,0,0)j.Position=UDim2.new(.5,0,1,0)j.Size=UDim2.new(f,0,f,0)j.Parent=z local r=createChatBubbleTail(v,UDim2.new(1,0,.5,0))r.Parent=j return z end function createChatImposter(G,f,v)local e=Instance.new("\073\109\097\103\101\076\097\098\101\108")e.Name="\068\105\097\108\111\103\080\108\097\099\101\104\111\108\100\101\114"e.Image="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047"..(tostring(G).."\046\112\110\103")e.BackgroundTransparency=1 e.BorderSizePixel=0 e.ImageColor3=Color3.fromRGB(0,0,0)e.Position=UDim2.new(0,0,-1.25,0)e.Size=UDim2.new(1,0,1,0)local z=Instance.new("\073\109\097\103\101\076\097\098\101\108")z.Name="\068\111\116\068\111\116\068\111\116"z.Image="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047"..(tostring(f).."\046\112\110\103")z.BackgroundTransparency=1 z.BorderSizePixel=0 z.Position=UDim2.new(.001,0,v,0)z.Size=UDim2.new(1,0,.7,0)z.Parent=e return e end local b={}b.ChatBubble={}b.ChatBubbleWithTail={}b.ScalingChatBubbleWithTail={}b.CharacterSortedMsg=e()


local function lerpLength(msg, min, max)
	return min + (max-min) * math.min(string.len(msg)/75.0, 1.0)
end

local function createFifo()
	local this = {}
	this.data = {}

	local emptyEvent = Instance.new("BindableEvent")
	this.Emptied = emptyEvent.Event

	function this:Size()
		return #this.data
	end

	function this:Empty()
		return this:Size() <= 0
	end

	function this:PopFront()
		table.remove(this.data, 1)
		if this:Empty() then emptyEvent:Fire() end
	end

	function this:Front()
		return this.data[1]
	end

	function this:Get(index)
		return this.data[index]
	end

	function this:PushBack(value)
		table.insert(this.data, value)
	end

	function this:GetData()
		return this.data
	end

	return this
end

local function createCharacterChats()
	local this = {}

	this.Fifo = createFifo()
	this.BillboardGui = nil

	return this
end

local function createMap()
	local this = {}
	this.data = {}
	local count = 0

	function this:Size()
		return count
	end

	function this:Erase(key)
		if this.data[key] then count = count - 1 end
		this.data[key] = nil
	end

	function this:Set(key, value)
		this.data[key] = value
		if value then count = count + 1 end
	end

	function this:Get(key)
		if not key then return end
		if not this.data[key] then
			this.data[key] = createCharacterChats()
			local emptiedCon = nil
			emptiedCon = this.data[key].Fifo.Emptied:connect(function()
				emptiedCon:disconnect()
				this:Erase(key)
			end)
		end
		return this.data[key]
	end

	function this:GetData()
		return this.data
	end

	return this
end

local function createChatLine(message, bubbleColor, isLocalPlayer)
	local this = {}

	function this:ComputeBubbleLifetime(msg, isSelf)
		if isSelf then
			return lerpLength(msg,8,15)
		else
			return lerpLength(msg,12,20)
		end
	end

	this.Origin = nil
	this.RenderBubble = nil
	this.Message = message
	this.BubbleDieDelay = this:ComputeBubbleLifetime(message, isLocalPlayer)
	this.BubbleColor = bubbleColor
	this.IsLocalPlayer = isLocalPlayer

	return this
end

local function createPlayerChatLine(player, message, isLocalPlayer)
	local this = createChatLine(message, BubbleColor.WHITE, isLocalPlayer)

	if player then
		this.User = player.Name
		this.Origin = player.Character
	end

	return this
end

local function createGameChatLine(origin, message, isLocalPlayer, bubbleColor)
	local this = createChatLine(message, bubbleColor, isLocalPlayer)
	this.Origin = origin

	return this
end

function createChatBubbleMain(filePrefix, sliceRect)
	local chatBubbleMain = Instance.new("ImageLabel")
	chatBubbleMain.Name = "ChatBubble"
	chatBubbleMain.ScaleType = Enum.ScaleType.Slice
	chatBubbleMain.SliceCenter = sliceRect
	chatBubbleMain.Image = "rbxasset://textures/" .. tostring(filePrefix) .. ".png"
	chatBubbleMain.BackgroundTransparency = 1
	chatBubbleMain.ImageColor3 = Color3.fromRGB(0,0,0)
	chatBubbleMain.BorderSizePixel = 0
	chatBubbleMain.Size = UDim2.new(1.0, 0, 1.0, 0)
	chatBubbleMain.Position = UDim2.new(0,0,0,0)

	return chatBubbleMain
end

function createChatBubbleTail(position, size)
	local chatBubbleTail = Instance.new("ImageLabel")
	chatBubbleTail.Name = "ChatBubbleTail"
	chatBubbleTail.Image = "rbxasset://textures/ui/dialog_tail.png"
	chatBubbleTail.BackgroundTransparency = 1
	chatBubbleTail.BorderSizePixel = 0
	chatBubbleTail.Position = position
	chatBubbleTail.Size = size
	chatBubbleTail.ImageColor3 = Color3.fromRGB(0,0,0)

	return chatBubbleTail
end

function createChatBubbleWithTail(filePrefix, position, size, sliceRect)
	local chatBubbleMain = createChatBubbleMain(filePrefix, sliceRect)

	local chatBubbleTail = createChatBubbleTail(position, size)
	chatBubbleTail.Parent = chatBubbleMain

	return chatBubbleMain
end

function createScaledChatBubbleWithTail(filePrefix, frameScaleSize, position, sliceRect)
	local chatBubbleMain = createChatBubbleMain(filePrefix, sliceRect)

	local frame = Instance.new("Frame")
	frame.Name = "ChatBubbleTailFrame"
	frame.BackgroundTransparency = 1
	frame.SizeConstraint = Enum.SizeConstraint.RelativeXX
	frame.BackgroundColor3 = Color3.fromRGB(0,0,0)
	frame.Position = UDim2.new(0.5, 0, 1, 0)
	frame.Size = UDim2.new(frameScaleSize, 0, frameScaleSize, 0)
	frame.Parent = chatBubbleMain

	local chatBubbleTail = createChatBubbleTail(position, UDim2.new(1,0,0.5,0))
	chatBubbleTail.Parent = frame

	return chatBubbleMain
end

function createChatImposter(filePrefix, dotDotDot, yOffset)
	local result = Instance.new("ImageLabel")
	result.Name = "DialogPlaceholder"
	result.Image = "rbxasset://textures/" .. tostring(filePrefix) .. ".png"
	result.BackgroundTransparency = 1
	result.BorderSizePixel = 0
	result.ImageColor3 =Color3.fromRGB(0,0,0)
	result.Position = UDim2.new(0, 0, -1.25, 0)
	result.Size = UDim2.new(1, 0, 1, 0)

	local image = Instance.new("ImageLabel")
	image.Name = "DotDotDot"
	image.Image = "rbxasset://textures/" .. tostring(dotDotDot) .. ".png"
	image.BackgroundTransparency = 1
	image.BorderSizePixel = 0
	image.Position = UDim2.new(0.001, 0, yOffset, 0)
	image.Size = UDim2.new(1, 0, 0.7, 0)
	image.Parent = result

	return result
end


local this = {}
this.ChatBubble = {}
this.ChatBubbleWithTail = {}
this.ScalingChatBubbleWithTail = {}
this.CharacterSortedMsg = createMap()
