Prompt: -- Text sizes

Response:
local TextBoundaries = Vector2.new(math.huge, math.huge)
local TITLE_SIZE = TextService:GetTextSize('Selection mode', 24/2, Enum.Font.SourceSans, TextBoundaries)
local HOTKEY_SIZE = TextService:GetTextSize('SHIFT-T', 24/2, Enum.Font.SourceSans, TextBoundaries)
local SCOPED_LABEL_SIZE = TextService:GetTextSize('Groups and parts', 25/2, Enum.Font.SourceSans, TextBoundaries)
local DIRECT_LABEL_SIZE = TextService:GetTextSize('Parts only', 25/2, Enum.Font.SourceSans, TextBoundaries)

local function Tooltip(props)
    return new('ImageLabel', {
        AnchorPoint = props.IsToolModeEnabled and
            Vector2.new(0, 1) or
            Vector2.new(0, 0);
        Position = props.IsToolModeEnabled and
            UDim2.new(0, 0, 0, -12/2) or
            UDim2.new(0, 0, 1, 12/2);
        BackgroundTransparency = 1;
        Image = 'rbxassetid://4445959523';
        ScaleType = Enum.ScaleType.Slice;
        SliceCenter = Rect.new(4, 4, 12, 12);
        ImageColor3 = Color3.fromRGB(67, 67, 67);
        Size = UDim2.new(0, TITLE_SIZE.X + 15/2 + HOTKEY_SIZE.X + 22/2, 0, 94/2);
        Visible = props.Visible;
    },
    {
        Arrow = new('Frame', {
            BackgroundColor3 = Color3.fromRGB(67, 67, 67);
            BorderSizePixel = 0;
            AnchorPoint = Vector2.new(0.5, 0.5);
            Position = props.IsToolModeEnabled and
                UDim2.new(0, 18/2, 1, 0) or
                UDim2.new(0, 18/2, 0, 0);
            Size = UDim2.new(0, 10/2, 0, 10/2);
            Rotation = 45;
        });
        Title = new('TextLabel', {
            BackgroundTransparency = 1;
            Font = Enum.Font.SourceSans;
            TextSize = 24/2;
            TextColor3 = Color3.new(1, 1, 1);
            TextTransparency = 1 - 0.6;
            Text = 'Selection mode';
            Size = UDim2.new(0, TITLE_SIZE.X, 0, TITLE_SIZE.Y);
            Position = UDim2.new(0, 8/2, 0, 5/2 + 2);
        });
        Hotkey = new('TextLabel', {
            BackgroundTransparency = 1;
            Font = Enum.Font.SourceSansSemibold;
            TextSize = 20/2;
            TextColor3 = Color3.new(1, 1, 1);
            TextTransparency = 0;
            Text = 'SHIFT-T';
            Size = UDim2.new(0, HOTKEY_SIZE.X, 0, HOTKEY_SIZE.Y);
            Position = UDim2.new(0, 8/2 + TITLE_SIZE.X + 15/2, 0, 5/2 + 2);
        });
        ScopedIcon = new('ImageLabel', {
            BackgroundTransparency = 1;
            Image = 'rbxassetid://4463020853';
            ImageTransparency = 1 - 0.4;
            Position = UDim2.fromOffset(
                8/2,
                5/2 + TITLE_SIZE.Y + 2
            );
            Size = UDim2.new(0, 28/2, 0, 28/2);
            ImageRectOffset = Vector2.new(0, 0);
            ImageRectSize = Vector2.new(14, 14);
        });
        ScopedLabel = new('TextLabel', {
            BackgroundTransparency = 1;
            Font = Enum.Font.SourceSans;
            TextSize = 25/2;
            TextColor3 = Color3.new(1, 1, 1);
            Text = 'Groups and parts';
            Size = UDim2.new(0, SCOPED_LABEL_SIZE.X, 0, SCOPED_LABEL_SIZE.Y);
            Position = UDim2.fromOffset(
                (8 + 26 + 8)/2,
                5/2 + TITLE_SIZE.Y + 2
            );
            TextXAlignment = Enum.TextXAlignment.Left;
        });
        DirectIcon = new('ImageLabel', {
            BackgroundTransparency = 1;
            Image = 'rbxassetid://4463020853';
            ImageTransparency = 1 - 0.4;
            Position = UDim2.fromOffset(
                8/2,
                5/2 + TITLE_SIZE.Y + 2 + SCOPED_LABEL_SIZE.Y + 1
            );
            Size = UDim2.new(0, 28/2, 0, 28/2);
            ImageRectOffset = Vector2.new(14, 0);
            ImageRectSize = Vector2.new(14, 14);
        });
        DirectLabel = new('TextLabel', {
            BackgroundTransparency = 1;
            Font = Enum.Font.SourceSans;
            TextSize = 25/2;
            TextColor3 = Color3.new(1, 1, 1);
            Text = 'Parts only';
            Size = UDim2.new(0, DIRECT_LABEL_SIZE.X, 0, DIRECT_LABEL_SIZE.Y);
            Position = UDim2.fromOffset(
                (8 + 26 + 8)/2,
                5/2 + TITLE_SIZE.Y + 2 + SCOPED_LABEL_SIZE.Y + 1
            );
            TextXAlignment = Enum.TextXAlignment.Left;
        });
    })
end

return Tooltip


Prompt: -- SERVICES --

Response:
local Players = game:GetService('Players')
local BadgeService = game:GetService('BadgeService')
local TweenService = game:GetService('TweenService')


Prompt:
--[=[
	Returns true if the value is a cancel token
	@param value any
	@return boolean
]=]

Response:
function CancelToken.isCancelToken(value)
	return type(value) == "table"
		and getmetatable(value) == CancelToken
end

local EMPTY_FUNCTION = function() end


Prompt: -- events

Response: Players.PlayerAdded:connect(HandlePlayer)


Prompt: -- only merge property defined on target

Response:
function mergeProps(source, target)
	if not source or not target then return end
	for prop, value in pairs(source) do
		if target[prop] ~= nil then
			target[prop] = value
		end
	end
end

function methods:CreateGuiObjects(targetParent)
	local userDefinedChatWindowStyle
	pcall(function()
		userDefinedChatWindowStyle= Chat:InvokeChatCallback(Enum.ChatCallbackType.OnCreatingChatWindow, nil)
	end)

	-- merge the userdefined settings with the ChatSettings
	mergeProps(userDefinedChatWindowStyle, ChatSettings)

	local BaseFrame = Instance.new("Frame")
	BaseFrame.BackgroundTransparency = 1
	BaseFrame.Active = ChatSettings.WindowDraggable
	BaseFrame.Parent = targetParent
    BaseFrame.AutoLocalize = false

	local ChatBarParentFrame = Instance.new("Frame")
	ChatBarParentFrame.Selectable = false
	ChatBarParentFrame.Name = "ChatBarParentFrame"
	ChatBarParentFrame.BackgroundTransparency = 1
	ChatBarParentFrame.Parent = BaseFrame

	local ChannelsBarParentFrame = Instance.new("Frame")
	ChannelsBarParentFrame.Selectable = false
	ChannelsBarParentFrame.Name = "ChannelsBarParentFrame"
	ChannelsBarParentFrame.BackgroundTransparency = 1
	ChannelsBarParentFrame.Position = UDim2.new(0, 0, 0, 0)
	ChannelsBarParentFrame.Parent = BaseFrame

	local ChatChannelParentFrame = Instance.new("Frame")
	ChatChannelParentFrame.Selectable = false
	ChatChannelParentFrame.Name = "ChatChannelParentFrame"
	ChatChannelParentFrame.BackgroundTransparency = 1
	ChatChannelParentFrame.BackgroundColor3 = ChatSettings.BackGroundColor
	ChatChannelParentFrame.BackgroundTransparency = 0.6
	ChatChannelParentFrame.BorderSizePixel = 0
	ChatChannelParentFrame.Parent = BaseFrame

	local ChatResizerFrame = Instance.new("ImageButton")
	ChatResizerFrame.Selectable = false
	ChatResizerFrame.Image = ""
	ChatResizerFrame.BackgroundTransparency = 0.6
	ChatResizerFrame.BorderSizePixel = 0
	ChatResizerFrame.Visible = false
	ChatResizerFrame.BackgroundColor3 = ChatSettings.BackGroundColor
	ChatResizerFrame.Active = true
	if bubbleChatOnly() then
		ChatResizerFrame.Position = UDim2.new(1, -ChatResizerFrame.AbsoluteSize.X, 0, 0)
	else
		ChatResizerFrame.Position = UDim2.new(1, -ChatResizerFrame.AbsoluteSize.X, 1, -ChatResizerFrame.AbsoluteSize.Y)
	end
	ChatResizerFrame.Parent = BaseFrame

	local ResizeIcon = Instance.new("ImageLabel")
	ResizeIcon.Selectable = false
	ResizeIcon.Size = UDim2.new(0.8, 0, 0.8, 0)
	ResizeIcon.Position = UDim2.new(0.2, 0, 0.2, 0)
	ResizeIcon.BackgroundTransparency = 1
	ResizeIcon.Image = "rbxassetid://261880743"
	ResizeIcon.Parent = ChatResizerFrame

	local function GetScreenGuiParent()
		--// Travel up parent list until you find the ScreenGui that the chat window is parented to
		local screenGuiParent = BaseFrame
		while (screenGuiParent and not screenGuiParent:IsA("ScreenGui")) do
			screenGuiParent = screenGuiParent.Parent
		end

		return screenGuiParent
	end

	local deviceType = DEVICE_DESKTOP

	local screenGuiParent = GetScreenGuiParent()
	if (screenGuiParent.AbsoluteSize.X <= PHONE_SCREEN_WIDTH) then
		deviceType = DEVICE_PHONE

	elseif (screenGuiParent.AbsoluteSize.X <= TABLET_SCREEN_WIDTH) then
		deviceType = DEVICE_TABLET

	end

	local checkSizeLock = false
	local function doCheckSizeBounds()
		if (checkSizeLock) then return end
		checkSizeLock = true

		if (not BaseFrame:IsDescendantOf(PlayerGui)) then return end

		local screenGuiParent = GetScreenGuiParent()

		local minWinSize = ChatSettings.MinimumWindowSize
		local maxWinSize = ChatSettings.MaximumWindowSize

		local forceMinY = ChannelsBarParentFrame.AbsoluteSize.Y + ChatBarParentFrame.AbsoluteSize.Y

		local minSizePixelX = (minWinSize.X.Scale * screenGuiParent.AbsoluteSize.X) + minWinSize.X.Offset
		local minSizePixelY = math.max((minWinSize.Y.Scale * screenGuiParent.AbsoluteSize.Y) + minWinSize.Y.Offset, forceMinY)

		local maxSizePixelX = (maxWinSize.X.Scale * screenGuiParent.AbsoluteSize.X) + maxWinSize.X.Offset
		local maxSizePixelY = (maxWinSize.Y.Scale * screenGuiParent.AbsoluteSize.Y) + maxWinSize.Y.Offset

		local absSizeX = BaseFrame.AbsoluteSize.X
		local absSizeY = BaseFrame.AbsoluteSize.Y

		if (absSizeX < minSizePixelX) then
			local offset = UDim2.new(0, minSizePixelX - absSizeX, 0, 0)
			BaseFrame.Size = BaseFrame.Size + offset

		elseif (absSizeX > maxSizePixelX) then
			local offset = UDim2.new(0, maxSizePixelX - absSizeX, 0, 0)
			BaseFrame.Size = BaseFrame.Size + offset

		end

		if (absSizeY < minSizePixelY) then
			local offset = UDim2.new(0, 0, 0, minSizePixelY - absSizeY)
			BaseFrame.Size = BaseFrame.Size + offset

		elseif (absSizeY > maxSizePixelY) then
			local offset = UDim2.new(0, 0, 0, maxSizePixelY - absSizeY)
			BaseFrame.Size = BaseFrame.Size + offset

		end

		local xScale = BaseFrame.AbsoluteSize.X / screenGuiParent.AbsoluteSize.X
		local yScale = BaseFrame.AbsoluteSize.Y / screenGuiParent.AbsoluteSize.Y

		-- cap chat window scale at a value smaller than 0.5 to prevent center of screen overlap
		if FFlagFixMouseCapture then
			xScale = math.min(xScale, 0.45)
			yScale = math.min(xScale, 0.45)
		end

		BaseFrame.Size = UDim2.new(xScale, 0, yScale, 0)

		checkSizeLock = false
	end

	BaseFrame.Changed:connect(function(prop)
		if (prop == "AbsoluteSize") then
			doCheckSizeBounds()
		end
	end)

	ChatResizerFrame.DragBegin:connect(function(startUdim)
		BaseFrame.Draggable = false
	end)

	local function UpdatePositionFromDrag(atPos)
		if ChatSettings.WindowDraggable == false and ChatSettings.WindowResizable == false then
			return
		end
		local newSize = atPos - BaseFrame.AbsolutePosition + ChatResizerFrame.AbsoluteSize
		BaseFrame.Size = UDim2.new(0, newSize.X, 0, newSize.Y)
		if bubbleChatOnly() then
			ChatResizerFrame.Position = UDim2.new(1, -ChatResizerFrame.AbsoluteSize.X, 0, 0)
		else
			ChatResizerFrame.Position = UDim2.new(1, -ChatResizerFrame.AbsoluteSize.X, 1, -ChatResizerFrame.AbsoluteSize.Y)
		end
	end

	ChatResizerFrame.DragStopped:connect(function(endX, endY)
		BaseFrame.Draggable = ChatSettings.WindowDraggable
		--UpdatePositionFromDrag(Vector2.new(endX, endY))
	end)

	local resizeLock = false
	ChatResizerFrame.Changed:connect(function(prop)
		if (prop == "AbsolutePosition" and not BaseFrame.Draggable) then
			if (resizeLock) then return end
			resizeLock = true

			UpdatePositionFromDrag(ChatResizerFrame.AbsolutePosition)

			resizeLock = false
		end
	end)

	local function CalculateChannelsBarPixelSize(textSize)
		if (deviceType == DEVICE_PHONE) then
			textSize = textSize or ChatSettings.ChatChannelsTabTextSizePhone
		else
			textSize = textSize or ChatSettings.ChatChannelsTabTextSize
		end

		local channelsBarTextYSize = textSize
		local chatChannelYSize = math.max(32, channelsBarTextYSize + 8) + 2

		return chatChannelYSize
	end

	local function CalculateChatBarPixelSize(textSize)
		if (deviceType == DEVICE_PHONE) then
			textSize = textSize or ChatSettings.ChatBarTextSizePhone
		else
			textSize = textSize or ChatSettings.ChatBarTextSize
		end

		local chatBarTextSizeY = textSize
		local chatBarYSize = chatBarTextSizeY + (7 * 2) + (5 * 2)

		return chatBarYSize
	end

	if bubbleChatOnly() then
		ChatBarParentFrame.Position = UDim2.new(0, 0, 0, 0)
		ChannelsBarParentFrame.Visible = false
		ChannelsBarParentFrame.Active = false
		ChatChannelParentFrame.Visible = false
		ChatChannelParentFrame.Active = false

		local useXScale = 0
		local useXOffset = 0

		local screenGuiParent = GetScreenGuiParent()

		if (deviceType == DEVICE_PHONE) then
			useXScale = ChatSettings.DefaultWindowSizePhone.X.Scale
			useXOffset = ChatSettings.DefaultWindowSizePhone.X.Offset

		elseif (deviceType == DEVICE_TABLET) then
			useXScale = ChatSettings.DefaultWindowSizeTablet.X.Scale
			useXOffset = ChatSettings.DefaultWindowSizeTablet.X.Offset

		else
			useXScale = ChatSettings.DefaultWindowSizeTablet.X.Scale
			useXOffset = ChatSettings.DefaultWindowSizeTablet.X.Offset

		end

		local chatBarYSize = CalculateChatBarPixelSize()

		BaseFrame.Size = UDim2.new(useXScale, useXOffset, 0, chatBarYSize)
		BaseFrame.Position = ChatSettings.DefaultWindowPosition

	else

		local screenGuiParent = GetScreenGuiParent()

		if (deviceType == DEVICE_PHONE) then
			BaseFrame.Size = ChatSettings.DefaultWindowSizePhone

		elseif (deviceType == DEVICE_TABLET) then
			BaseFrame.Size = ChatSettings.DefaultWindowSizeTablet

		else
			BaseFrame.Size = ChatSettings.DefaultWindowSizeDesktop

		end

		BaseFrame.Position = ChatSettings.DefaultWindowPosition

	end

	if (deviceType == DEVICE_PHONE) then
		ChatSettings.ChatWindowTextSize = ChatSettings.ChatWindowTextSizePhone
		ChatSettings.ChatChannelsTabTextSize = ChatSettings.ChatChannelsTabTextSizePhone
		ChatSettings.ChatBarTextSize = ChatSettings.ChatBarTextSizePhone
	end

	local function UpdateDraggable(enabled)
		BaseFrame.Active = enabled
		BaseFrame.Draggable = enabled
	end

	local function UpdateResizable(enabled)
		ChatResizerFrame.Visible = enabled
		ChatResizerFrame.Draggable = enabled

		local frameSizeY = ChatBarParentFrame.Size.Y.Offset

		if (enabled) then
			ChatBarParentFrame.Size = UDim2.new(1, -frameSizeY - 2, 0, frameSizeY)
			if not bubbleChatOnly() then
				ChatBarParentFrame.Position = UDim2.new(0, 0, 1, -frameSizeY)
			end
		else
			ChatBarParentFrame.Size = UDim2.new(1, 0, 0, frameSizeY)
			if not bubbleChatOnly() then
				ChatBarParentFrame.Position = UDim2.new(0, 0, 1, -frameSizeY)
			end
		end
	end

	local function UpdateChatChannelParentFrameSize()
		local channelsBarSize = CalculateChannelsBarPixelSize()
		local chatBarSize = CalculateChatBarPixelSize()

		if (ChatSettings.ShowChannelsBar) then
			ChatChannelParentFrame.Size = UDim2.new(1, 0, 1, -(channelsBarSize + chatBarSize + 2 + 2))
			ChatChannelParentFrame.Position = UDim2.new(0, 0, 0, channelsBarSize + 2)

		else
			ChatChannelParentFrame.Size = UDim2.new(1, 0, 1, -(chatBarSize + 2 + 2))
			ChatChannelParentFrame.Position = UDim2.new(0, 0, 0, 2)

		end
	end

	local function UpdateChatChannelsTabTextSize(size)
		local channelsBarSize = CalculateChannelsBarPixelSize(size)
		ChannelsBarParentFrame.Size = UDim2.new(1, 0, 0, channelsBarSize)

		UpdateChatChannelParentFrameSize()
	end

	local function UpdateChatBarTextSize(size)
		local chatBarSize = CalculateChatBarPixelSize(size)

		ChatBarParentFrame.Size = UDim2.new(1, 0, 0, chatBarSize)
		if not bubbleChatOnly() then
			ChatBarParentFrame.Position = UDim2.new(0, 0, 1, -chatBarSize)
		end

		ChatResizerFrame.Size = UDim2.new(0, chatBarSize, 0, chatBarSize)
		ChatResizerFrame.Position = UDim2.new(1, -chatBarSize, 1, -chatBarSize)

		UpdateChatChannelParentFrameSize()
		UpdateResizable(ChatSettings.WindowResizable)
	end

	local function UpdateShowChannelsBar(enabled)
		ChannelsBarParentFrame.Visible = enabled
		UpdateChatChannelParentFrameSize()
	end

	UpdateChatChannelsTabTextSize(ChatSettings.ChatChannelsTabTextSize)
	UpdateChatBarTextSize(ChatSettings.ChatBarTextSize)
	UpdateDraggable(ChatSettings.WindowDraggable)
	UpdateResizable(ChatSettings.WindowResizable)
	UpdateShowChannelsBar(ChatSettings.ShowChannelsBar)

	ChatSettings.SettingsChanged:connect(function(setting, value)
		if (setting == "WindowDraggable") then
			UpdateDraggable(value)

		elseif (setting == "WindowResizable") then
			UpdateResizable(value)

		elseif (setting == "ChatChannelsTabTextSize") then
			UpdateChatChannelsTabTextSize(value)

		elseif (setting == "ChatBarTextSize") then
			UpdateChatBarTextSize(value)

		elseif (setting == "ShowChannelsBar") then
			UpdateShowChannelsBar(value)

		end
	end)

	self.GuiObject = BaseFrame

	self.GuiObjects.BaseFrame = BaseFrame
	self.GuiObjects.ChatBarParentFrame = ChatBarParentFrame
	self.GuiObjects.ChannelsBarParentFrame = ChannelsBarParentFrame
	self.GuiObjects.ChatChannelParentFrame = ChatChannelParentFrame
	self.GuiObjects.ChatResizerFrame = ChatResizerFrame
	self.GuiObjects.ResizeIcon = ResizeIcon
	self:AnimGuiObjects()
end

function methods:GetChatBar()
	return self.ChatBar
end

function methods:RegisterChatBar(ChatBar)
	self.ChatBar = ChatBar
	self.ChatBar:CreateGuiObjects(self.GuiObjects.ChatBarParentFrame)
end

function methods:RegisterChannelsBar(ChannelsBar)
	self.ChannelsBar = ChannelsBar
	self.ChannelsBar:CreateGuiObjects(self.GuiObjects.ChannelsBarParentFrame)
end

function methods:RegisterMessageLogDisplay(MessageLogDisplay)
	self.MessageLogDisplay = MessageLogDisplay
	self.MessageLogDisplay.GuiObject.Parent = self.GuiObjects.ChatChannelParentFrame
end

function methods:AddChannel(channelName)
	if (self:GetChannel(channelName)) then
		error("Channel '" .. channelName .. "' already exists!")
		return
	end

	local channel = moduleChatChannel.new(channelName, self.MessageLogDisplay)
	self.Channels[channelName:lower()] = channel

	channel:SetActive(false)

	local tab = self.ChannelsBar:AddChannelTab(channelName)
	tab.NameTag.MouseButton1Click:connect(function()
		self:SwitchCurrentChannel(channelName)
	end)

	channel:RegisterChannelTab(tab)

	return channel
end

function methods:GetFirstChannel()
	--// Channels are not indexed numerically, so this function is necessary.
	--// Grabs and returns the first channel it happens to, or nil if none exist.
	for i, v in pairs(self.Channels) do
		return v
	end
	return nil
end

function methods:RemoveChannel(channelName)
	if (not self:GetChannel(channelName)) then
		error("Channel '" .. channelName .. "' does not exist!")
	end

	local indexName = channelName:lower()

	local needsChannelSwitch = false
	if (self.Channels[indexName] == self:GetCurrentChannel()) then
		needsChannelSwitch = true

		self:SwitchCurrentChannel(nil)
	end

	self.Channels[indexName]:Destroy()
	self.Channels[indexName] = nil

	self.ChannelsBar:RemoveChannelTab(channelName)

	if (needsChannelSwitch) then
		local generalChannelExists = (self:GetChannel(ChatSettings.GeneralChannelName) ~= nil)
		local removingGeneralChannel = (indexName == ChatSettings.GeneralChannelName:lower())

		local targetSwitchChannel = nil

		if (generalChannelExists and not removingGeneralChannel) then
			targetSwitchChannel = ChatSettings.GeneralChannelName
		else
			local firstChannel = self:GetFirstChannel()
			targetSwitchChannel = (firstChannel and firstChannel.Name or nil)
		end

		self:SwitchCurrentChannel(targetSwitchChannel)
	end

	if not ChatSettings.ShowChannelsBar then
		if self.ChatBar.TargetChannel == channelName then
			self.ChatBar:SetChannelTarget(ChatSettings.GeneralChannelName)
		end
	end
end

function methods:GetChannel(channelName)
	return channelName and self.Channels[channelName:lower()] or nil
end

function methods:GetTargetMessageChannel()
	if (not ChatSettings.ShowChannelsBar) then
		return self.ChatBar.TargetChannel
	else
		local curChannel = self:GetCurrentChannel()
		return curChannel and curChannel.Name
	end
end

function methods:GetCurrentChannel()
	return self.CurrentChannel
end

function methods:SwitchCurrentChannel(channelName)
	if (not ChatSettings.ShowChannelsBar) then
		local targ = self:GetChannel(channelName)
		if (targ) then
			self.ChatBar:SetChannelTarget(targ.Name)
		end

		channelName = ChatSettings.GeneralChannelName
	end

	local cur = self:GetCurrentChannel()
	local new = self:GetChannel(channelName)
	if new == nil then
		error(string.format("Channel '%s' does not exist.", channelName))
	end

	if (new ~= cur) then
		if (cur) then
			cur:SetActive(false)
			local tab = self.ChannelsBar:GetChannelTab(cur.Name)
			tab:SetActive(false)
		end

		if (new) then
			new:SetActive(true)
			local tab = self.ChannelsBar:GetChannelTab(new.Name)
			tab:SetActive(true)
		end

		self.CurrentChannel = new
	end

end

function methods:UpdateFrameVisibility()
	self.GuiObject.Visible = (self.Visible and self.CoreGuiEnabled)
end

function methods:GetVisible()
	return self.Visible
end

function methods:SetVisible(visible)
	self.Visible = visible
	self:UpdateFrameVisibility()
end

function methods:GetCoreGuiEnabled()
	return self.CoreGuiEnabled
end

function methods:SetCoreGuiEnabled(enabled)
	self.CoreGuiEnabled = enabled
	self:UpdateFrameVisibility()
end

function methods:EnableResizable()
	self.GuiObjects.ChatResizerFrame.Active = true
end

function methods:DisableResizable()
	self.GuiObjects.ChatResizerFrame.Active = false
end

function methods:FadeOutBackground(duration)
	self.ChannelsBar:FadeOutBackground(duration)
	self.MessageLogDisplay:FadeOutBackground(duration)
	self.ChatBar:FadeOutBackground(duration)

	self.AnimParams.Background_TargetTransparency = 1
	self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end

function methods:FadeInBackground(duration)
	self.ChannelsBar:FadeInBackground(duration)
	self.MessageLogDisplay:FadeInBackground(duration)
	self.ChatBar:FadeInBackground(duration)

	self.AnimParams.Background_TargetTransparency = 0.6
	self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end

function methods:FadeOutText(duration)
	self.MessageLogDisplay:FadeOutText(duration)
	self.ChannelsBar:FadeOutText(duration)
end

function methods:FadeInText(duration)
	self.MessageLogDisplay:FadeInText(duration)
	self.ChannelsBar:FadeInText(duration)
end

function methods:AnimGuiObjects()
	self.GuiObjects.ChatChannelParentFrame.BackgroundTransparency = self.AnimParams.Background_CurrentTransparency
	self.GuiObjects.ChatResizerFrame.BackgroundTransparency = self.AnimParams.Background_CurrentTransparency
	self.GuiObjects.ResizeIcon.ImageTransparency = self.AnimParams.Background_CurrentTransparency
end

function methods:InitializeAnimParams()
	self.AnimParams.Background_TargetTransparency = 0.6
	self.AnimParams.Background_CurrentTransparency = 0.6
	self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(0)
end

function methods:Update(dtScale)
	self.ChatBar:Update(dtScale)
	self.ChannelsBar:Update(dtScale)
	self.MessageLogDisplay:Update(dtScale)

	self.AnimParams.Background_CurrentTransparency = CurveUtil:Expt(
			self.AnimParams.Background_CurrentTransparency,
			self.AnimParams.Background_TargetTransparency,
			self.AnimParams.Background_NormalizedExptValue,
			dtScale
	)

	self:AnimGuiObjects()
end


Prompt:
-- setup emote chat hook
--[[game:GetService("Players").LocalPlayer.Chatted:connect(function(msg)
	local emote = ""
	if (string.sub(msg, 1, 3) == "/e ") then
		emote = string.sub(msg, 4)
	elseif (string.sub(msg, 1, 7) == "/emote ") then
		emote = string.sub(msg, 8)
	end

	if (pose == "Standing" and emoteNames[emote] ~= nil) then
		playAnimation(emote, EMOTE_TRANSITION_TIME, Humanoid)
	end
end)--]]


Prompt: -- Ego's version

Response:
local region = {};

function region.new(cframe, size)
	local self = setmetatable({}, {__index = region});

	self.CFrame = cframe;
	self.Planes = {
		{n = cframe:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Top)), d = -size.y / 2};
		{n = cframe:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Bottom)), d = -size.y / 2};
		{n = cframe:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Left)), d = -size.x / 2};
		{n = cframe:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Right)), d = -size.x / 2};
		{n = cframe:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Front)), d = -size.z / 2};
		{n = cframe:vectorToWorldSpace(Vector3.FromNormalId(Enum.NormalId.Back)), d = -size.z / 2};
	};

	return self;
end;

function getCorners(part)
	local size, corners = part.Size / 2, {};
	for x = -1, 1, 2 do
		for y = -1, 1, 2 do
			for z = -1, 1, 2 do
				table.insert(corners, (part.CFrame * CFrame.new(size * Vector3.new(x, y, z))).p);
			end;
		end;
	end;
	return corners;
end;

function region:CastPart(part)
	local corners = getCorners(part);
	for _, corner in next, corners do
		local position = corner - self.CFrame.p;
		local isInRegion = true;
		for _, plane in next, self.Planes do
			if (position:Dot(plane.n) + plane.d) >= 0 then
				isInRegion = false;
				break;
			end;
		end;
		if isInRegion then
			return true;
		end;
	end;
	return false;
end;

return region;


Prompt: -------------- I'm not responsible for any PAIN if you edit past this (pun intended)

Response:
local blood_folder = Instance.new("Folder",game.Workspace)
blood_folder.Name = "Blood.Splatter.Particles"

function create_blood_splatter(player_class)
	local blood_parts = {"LeftFoot","LeftHand","LeftLowerArm","LeftLowerLeg","LeftUpperArm","LeftUpperLeg","LowerTorso","RightFoot","RightHand","RightLowerArm","RightLowerLeg","RightUpperArm","RightUpperLeg","UpperTorso","Head"}
	local chosen_part
	if(player_class.humanoid.Health <= 0) then
		repeat wait() chosen_part = blood_parts[math.random(1,#blood_parts)] until player_class.character:FindFirstChild(chosen_part)
		chosen_part = player_class.character[chosen_part]
		local blood_emmiter = script.Blood:Clone()
		blood_emmiter.Parent = chosen_part
		blood_emmiter.Enabled = true
	else
		chosen_part = player_class.torso
	end
	local ray = Ray.new(chosen_part.Position, Vector3.new(0,-100,0))
    local hit, position = game.Workspace:FindPartOnRayWithIgnoreList(ray, {blood_folder , unpack(player_class.character:GetChildren())} , true)
	if(hit) then
		local blood = Instance.new("Part",blood_folder)
		blood.Anchored = true
		blood.CanCollide = false
		blood.Transparency = 1
		blood.Name = "Particle_Blood"
		blood.FormFactor = Enum.FormFactor.Custom
		blood.Size = Vector3.new(0.01 , 0.1 , 0.01)
		blood.CFrame = CFrame.new(position)
		local blood_decal = Instance.new("Decal",blood)
		blood_decal.Transparency = 1
		blood_decal.Texture = "http://www.roblox.com/asset/?id=" .. blood_textures[math.random(1,#blood_textures)]
		blood_decal.Face = "Top"
		game.Debris:AddItem(blood,settings.remove_time+20)
		local edit_blood = coroutine.wrap(function()
			local original_size = blood.Size
			local original_transparency = blood_decal.Transparency
			local new_transparency = math.random(settings.max_transparency*100,settings.min_transparency*100)/100
			local new_size = Vector3.new(math.random(settings.min_size_x*100,settings.max_size_x*100)/100 , blood.Size.Y , math.random(settings.min_size_z*100,settings.max_size_z*100)/100)
			local tran_tw_time = math.random(settings.tran_tw_time_min*100,settings.tran_tw_time_max*100)/100
			local size_tw_time = math.random(settings.size_tw_time_min*100,settings.size_tw_time_max*100)/100
			for i = 1,10*tran_tw_time do
				wait()
				local perc = i/(10*tran_tw_time)
				blood_decal.Transparency = original_transparency - (perc*new_transparency)
			end
			for i = 1,10*size_tw_time do
				wait()
				local perc = i/(10*size_tw_time)
				blood.Size = Vector3.new(original_size.X+(perc*new_size.X) , original_size.Y , original_size.Z+(perc*new_size.Z))
			end
			wait(settings.remove_time)
			blood:Destroy()
		end)
		edit_blood()
	end
end

function monitor_character(player_class)
	local last_health = player_class.humanoid.Health
	player_class.humanoid.HealthChanged:connect(function()
		if(player_class.humanoid.Health < last_health) then
			if(last_health - player_class.humanoid.Health >= settings.damage_inc) then
				for i = 1,settings.splatters_per_health_inc*((last_health - player_class.humanoid.Health)/settings.damage_inc) do
					create_blood_splatter(player_class)
					if(settings.max_splatter_time > 0) then
						wait(math.random(settings.min_splatter_time*100,settings.max_splatter_time*100)/100)
					end
				end
			end
		end
		last_health = player_class.humanoid.Health
	end)
end

function monitor_player(player)
	repeat wait() until player.Character ~= nil
	player.CharacterAdded:connect(function()
		local player_class = {
			player = player,
			character = player.Character,
			torso = player.Character:WaitForChild("LowerTorso"),
			head = player.Character:WaitForChild("Head"),
			humanoid = player.Character:WaitForChild("Humanoid"),
		}
		monitor_character(player_class)
	end)
	local player_class = {
		player = player,
		character = player.Character,
		torso = player.Character:WaitForChild("UpperTorso"),
		head = player.Character:WaitForChild("Head"),
		humanoid = player.Character:WaitForChild("Humanoid"),
	}
	monitor_character(player_class)
end

game.Players.PlayerAdded:connect(function(player)
	monitor_player(player)
end)

for i,v in ipairs(game.Players:GetChildren()) do
	if(v.ClassName == "Player") then
		monitor_player(v)
	end
end


Prompt:
--[[
[Instructions]
 - Put the Script inside a Seat.
 - Remove the GUI already inside the Script (It's just an example).
 - Put your own GUI inside the script.
 - Re-name the GUI to "GUI" (Without the quotation marks " ")

It should work, but tell me if it doesn't.
--]]


Prompt: --//Services//--

Response: local Debris = game:GetService("Debris")


Prompt:
--edit the function below to return true when you want this response/prompt to be valid
--player is the player speaking to the dialogue, and dialogueFolder is the object containing the dialogue data

Response:
return function(player, dialogueFolder)
	local plrData = require(game.ReplicatedStorage.Source.Modules.Util):GetPlayerData(player)
	return plrData.Money.Gold.Value >= 20
end


Prompt: -- Local private variables and constants

Response:
local ZERO_VECTOR2 = Vector2.new(0,0)

local tweenAcceleration = math.rad(220)		--Radians/Second^2
local tweenSpeed = math.rad(0)				--Radians/Second
local tweenMaxSpeed = math.rad(250)			--Radians/Second
local TIME_BEFORE_AUTO_ROTATE = 2.0 		--Seconds, used when auto-aligning camera with vehicles
local PORTRAIT_OFFSET = Vector3.new(0, 2, 0)
local MOBILE_OFFSET = Vector3.new(0, 1, 0)

local INITIAL_CAMERA_ANGLE = CFrame.fromOrientation(math.rad(-15), 0, 0)


Prompt: --- Skill

Response:
local UIS = game:GetService("UserInputService")
local plr = game.Players.LocalPlayer
local Mouse = plr:GetMouse()
local Debounce = true
Player = game.Players.LocalPlayer

UIS.InputBegan:Connect(function(Input)
	if Input.KeyCode == Enum.KeyCode.Z and Debounce == true and Tool.Equip.Value == true and Tool.Active.Value == "None" then
		Debounce = false
		Tool.Active.Value = "LightBarrage"
		Track1 = Player.Character.Humanoid:LoadAnimation(script.Anim01)
		Track1:Play()
		wait(0.3)
		script.Fire:FireServer(plr)
	local hum =  Player.Character.Humanoid
	for i = 1,30 do
		wait()
		hum.CameraOffset = Vector3.new(
			math.random(0.1,0.1),
			math.random(0.1,0.1),
			math.random(0.1,0.1)
		)
	end
	hum.CameraOffset = Vector3.new(0,0,0)
		Tool.Active.Value = "None"
		wait(2)
		Debounce = true
	end
end)


Prompt:
--[[**
	ensures Lua primitive callback type

	@param value The value to check against

	@returns True iff the condition is satisfied, false otherwise
**--]]

Response: t.callback = primitive("function")


Prompt: --// # key, ManOff

Response:
mouse.KeyUp:connect(function(key)
	if key=="f" then
		veh.Lightbar.middle.Man:Stop()
		veh.Lightbar.middle.Wail.Volume = 10
		veh.Lightbar.middle.Yelp.Volume = 10
		veh.Lightbar.middle.Priority.Volume = 10
		script.Parent.Parent.Sirens.Man.BackgroundColor3 = Color3.fromRGB(62, 62, 62)
		veh.Lightbar.MANUAL.Transparency = 1
	end
end)


Prompt: -- Static variables

Response: local _SPEEDEROBJECTSCOLLISIONGROUP = "SpeederObjects"


Response:
gui.Track.Text = radio.TName.Value
radio.TName.Changed:connect(function()
	gui.Track.Text = radio.TName.Value
	seat.Parent.Body.Dash.S.G.Song.Text = radio.TName.Value
end)
gui.Stop.MouseButton1Click:connect(function()
	if radio.Stopped.Value == false then
		radio.Stopped.Value = true
	end
end)
gui.Pause.MouseButton1Click:connect(function()
	if radio.Paused.Value == false and radio.Stopped.Value == false then
		radio.Paused.Value = true
	end
end)
gui.Play.MouseButton1Click:connect(function()
	if radio.Stopped.Value == true then
		radio.Play.Value = not radio.Play.Value
	else
		if radio.Paused.Value == true then
			radio.Paused.Value = false
		end
	end
end)
gui.Forward.MouseButton1Click:connect(function()
	local n = radio.Track.Value+1
	if n>#radio.Songs:GetChildren() then
		n = 1
	end
	radio.Track.Value = n
end)
gui.Back.MouseButton1Click:connect(function()
	local n = radio.Track.Value-1
	if n<=0 then
		n = #radio.Songs:GetChildren()
	end
	radio.Track.Value = n
end)
gui.AutoplayOn.MouseButton1Click:connect(function()
	if radio.Autoplay.Value == true then
		radio.Autoplay.Value = false
	end
end)
gui.AutoplayOff.MouseButton1Click:connect(function()
	if radio.Autoplay.Value == false then
		radio.Autoplay.Value = true
	end
end)
gui.List.MouseButton1Click:connect(function()
	gui.Menu.Visible=not gui.Menu.Visible
end)
gui.Id.MouseButton1Click:connect(function()
	gui.IdPlayer.Visible=not gui.IdPlayer.Visible
	if gui.IdPlayer.Visible then gui.Id.Rotation=180 else gui.Id.Rotation=0 end
end)
gui.IdPlayer.Play.MouseButton1Click:connect(function()
	if radio.IdPlay.Value==gui.IdPlayer.TextBox.Text then
		radio.IdPlay.Value=""
	wait()
	end
	radio.IdPlay.Value=gui.IdPlayer.TextBox.Text
end)
for i,v in pairs(gui.Menu:GetChildren()) do
	v.MouseButton1Click:connect(function()
		radio.Track.Value = i
	end)
end
function Stopped()
	if radio.Stopped.Value == true then
		gui.Pause.Visible = false
		gui.Play.Visible = true
	else
		gui.Play.Visible = false
		gui.Pause.Visible = true
	end
end
function Paused()
	if radio.Paused.Value == true then
		gui.Pause.Visible = false
		gui.Play.Visible = true
	else
		if radio.Stopped.Value == false then
			gui.Play.Visible = false
			gui.Pause.Visible = true
		end
	end
end
function Autoplay()
	if radio.Autoplay.Value == true then
		gui.AutoplayOff.Visible = false
		gui.AutoplayOn.Visible = true
	else
		gui.AutoplayOn.Visible = false
		gui.AutoplayOff.Visible = true
	end
end
radio.Stopped.Changed:connect(Stopped)
radio.Paused.Changed:connect(Paused)
radio.Autoplay.Changed:connect(Autoplay)
Stopped()
Paused()
Autoplay()
while wait(.5) do
	if seat:FindFirstChild("SeatWeld") == nil then
		script.Parent:Destroy()
	end
end


Prompt:
-- Display assertion for the report when a test fails.
-- New format: rejects/resolves, not, and matcher name have black color
-- Old format: matcher name has dim color

Response:
function matcherHint(matcherName: string, received: string?, expected: string?, options: MatcherHintOptions?): string
	received = received or "received"
	expected = expected or "expected"
	options = options or {}

	--[[
		ROBLOX TODO: Remove the "if options" check once it can pass through
		Luau cleanly and define all of the variables in-line i.e.
		local comment = options.comment or ""
	]]
	local comment, expectedColor, isDirectExpectCall, isNot, promise, receivedColor, secondArgument, secondArgumentColor
	if options then
		comment = options.comment or ""
		expectedColor = options.expectedColor or EXPECTED_COLOR
		isDirectExpectCall = options.isDirectExpectCall or false
		isNot = options.isNot or false
		promise = options.promise or ""
		receivedColor = options.receivedColor or RECEIVED_COLOR
		secondArgument = options.secondArgument or ""
		secondArgumentColor = options.secondArgumentColor or EXPECTED_COLOR
	end

	local hint = ""
	local dimString = "expect" -- concatenate adjacent dim substrings

	if not isDirectExpectCall and received ~= "" then
		hint = hint .. DIM_COLOR(dimString .. "(") .. receivedColor(received)
		dimString = ")"
	end

	if promise ~= "" then
		hint = hint .. DIM_COLOR(dimString .. ".") .. promise
		dimString = ""
	end

	if isNot then
		hint = hint .. DIM_COLOR(dimString .. ".") .. "never"
		dimString = ""
	end

	if string.find(matcherName, "%.") then
		-- Old format: for backward compatibility,
		-- especially without promise or isNot options
		dimString = dimString .. matcherName
	else
		-- New format: omit period from matcherName arg
		hint = hint .. DIM_COLOR(dimString .. ".") .. matcherName
		dimString = ""
	end

	if expected == "" then
		dimString = dimString .. "()"
	else
		hint = hint .. DIM_COLOR(dimString .. "(") .. expectedColor(expected)
		if secondArgument ~= "" then
			hint = hint .. DIM_COLOR(", ") .. secondArgumentColor(secondArgument)
		end
		dimString = ")"
	end

	if comment ~= "" then
		dimString = dimString .. " -- " .. comment
	end

	if dimString ~= "" then
		hint = hint .. DIM_COLOR(dimString)
	end

	return hint
end

return {
	EXPECTED_COLOR = EXPECTED_COLOR,
	RECEIVED_COLOR = RECEIVED_COLOR,
	INVERTED_COLOR = INVERTED_COLOR,
	BOLD_WEIGHT = BOLD_WEIGHT,
	DIM_COLOR = DIM_COLOR,

	SUGGEST_TO_CONTAIN_EQUAL = SUGGEST_TO_CONTAIN_EQUAL,

	stringify = stringify,
	highlightTrailingWhitespace = highlightTrailingWhitespace,
	printReceived = printReceived,
	printExpected = printExpected,
	printWithType = printWithType,
	ensureNoExpected = ensureNoExpected,
	ensureActualIsNumber = ensureActualIsNumber,
	ensureExpectedIsNumber = ensureExpectedIsNumber,
	ensureNumbers = ensureNumbers,
	ensureExpectedIsNonNegativeInteger = ensureExpectedIsNonNegativeInteger,
	printDiffOrStringify = printDiffOrStringify,
	diff = diff,
	pluralize = pluralize,
	getLabelPrinter = getLabelPrinter,
	matcherErrorMessage = matcherErrorMessage,
	matcherHint = matcherHint,
}


Prompt: --[[ Script Variables ]]

Response:
--
while not Players.LocalPlayer do
	wait()
end

local lastInputType = nil
local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer:WaitForChild('PlayerGui')
local IsTouchDevice = UserInputService.TouchEnabled
local UserMovementMode = IsTouchDevice and GameSettings.TouchMovementMode or GameSettings.ComputerMovementMode
local DevMovementMode = IsTouchDevice and LocalPlayer.DevTouchMovementMode or LocalPlayer.DevComputerMovementMode
local IsUserChoice = (IsTouchDevice and DevMovementMode == Enum.DevTouchMovementMode.UserChoice) or (DevMovementMode == Enum.DevComputerMovementMode.UserChoice)
local TouchGui = nil
local TouchControlFrame = nil
local IsModalEnabled = UserInputService.ModalEnabled
local BindableEvent_OnFailStateChanged = nil
local isJumpEnabled = false


Prompt: --// All global vars will be wiped/replaced except script

Response:
return function(data, env)
	if env then
		setfenv(1, env)
	end
	local gui = client.UI.Prepare(script.Parent.Parent) -- Change it to a TextLabel to avoid chat clearing
	local playergui = service.PlayerGui
	local frame = gui.Frame
	local msg = gui.Frame.Message
	local ttl = gui.Frame.Title

	local gIndex = data.gIndex
	local gTable = data.gTable

	local title = data.Title
	local message = data.Message
	local scroll = data.Scroll
	local tim = data.Time

	if not data.Message or not data.Title then gui:Destroy() end

	ttl.Text = title
	msg.Text = message
	ttl.TextTransparency = 1
	msg.TextTransparency = 1
	ttl.TextStrokeTransparency = 1
	msg.TextStrokeTransparency = 1
	frame.BackgroundTransparency = 1

	local blur = service.New("BlurEffect")
	blur.Enabled = false
	blur.Size = 0
	blur.Parent = service.Workspace.CurrentCamera

	local fadeSteps = 10
	local blurSize = 10
	local textFade = 0.1
	local strokeFade = 0.5
	local frameFade = 0.3

	local blurStep = blurSize/fadeSteps
	local frameStep = frameFade/fadeSteps
	local textStep = 0.1
	local strokeStep = 0.1
	local gone = false

	local function fadeIn()
		if not gone then
			blur.Enabled = true
			gTable:Ready()
			--gui.Parent = service.PlayerGui
			for i = 1,fadeSteps do
				if blur.Size<blurSize then
					blur.Size = blur.Size+blurStep
				end
				if msg.TextTransparency>textFade then
					msg.TextTransparency = msg.TextTransparency-textStep
					ttl.TextTransparency = ttl.TextTransparency-textStep
				end
				if msg.TextStrokeTransparency>strokeFade then
					msg.TextStrokeTransparency = msg.TextStrokeTransparency-strokeStep
					ttl.TextStrokeTransparency = ttl.TextStrokeTransparency-strokeStep
				end
				if frame.BackgroundTransparency>frameFade then
					frame.BackgroundTransparency = frame.BackgroundTransparency-frameStep
				end
				wait(1/60)
			end
		end
	end

	local function fadeOut()
		if not gone then
			for i = 1,fadeSteps do
				if blur.Size>0 then
					blur.Size = blur.Size-blurStep
				end
				if msg.TextTransparency<1 then
					msg.TextTransparency = msg.TextTransparency+textStep
					ttl.TextTransparency = ttl.TextTransparency+textStep
				end
				if msg.TextStrokeTransparency<1 then
					msg.TextStrokeTransparency = msg.TextStrokeTransparency+strokeStep
					ttl.TextStrokeTransparency = ttl.TextStrokeTransparency+strokeStep
				end
				if frame.BackgroundTransparency<1 then
					frame.BackgroundTransparency = frame.BackgroundTransparency+frameStep
				end
				wait(1/60)
			end
			blur.Enabled = false
			blur:Destroy()
			service.UnWrap(gui):Destroy()
			gone = true
		end
	end

	gTable.CustomDestroy = function()
		if not gone then
			gone = true
			pcall(fadeOut)
		end

		pcall(function() service.UnWrap(gui):Destroy() end)
		pcall(function() blur:Destroy() end)
	end

	--[[if not scroll then
		msg.Text = message
	else
		Routine(function()
			wait(0.5)
			for i = 1, #message do
				msg.Text = msg.Text .. message:sub(i,i)
				wait(0.05)
			end
		end)
	end--]] -- For now?

	fadeIn()
	wait(tim or 5)
	if not gone then
		fadeOut()
	end

	--[[

	frame.Position = UDim2.new(0.5,-175,-1.5,0)

	gui.Parent = playergui

	frame:TweenPosition(UDim2.new(0.5,-175,0.25,0),nil,nil,0.5)

	if not scroll then
		msg.Text = message
		wait(tim or 10)
	else
		wait(0.5)
		for i = 1, #message do
			msg.Text = msg.Text .. message:sub(i,i)
			wait(0.05)
		end
		wait(tim or 5)
	end

	if frame then
		frame:TweenPosition(UDim2.new(0.5,-175,-1.5,0),nil,nil,0.5)
		wait(1)
		gui:Destroy()
	end
	--]]
end


Prompt: -- Public

Response:
function Utility.fastRemove(tbl: {number: any}, index: number) -- would use {any}, but it makes the linter angry
    local n = #tbl
    tbl[index] = tbl[n]
    tbl[n] = nil
end

function Utility.ser(...)
	local str = ''
	for _, num in next, {...} do
		str = str..math.floor(num)
	end

	return tonumber(str)
end

function Utility.toScale(scale: number, offset: number, parentSize: number): number
	return (offset / parentSize) + scale
end

function Utility.toOffset(scale: number, offset: number, parentSize: number): number
	return (scale * parentSize) + offset
end

function Utility.convert(obj: GuiObject | UILayout, prop: string, T: string): UDim2 | UDim
	local parentSize = obj.Parent.AbsoluteSize
	local ud = obj[prop]

	local to = T == 'Scale' and Utility.toScale or Utility.toOffset
	if typeof(obj[prop]) == 'UDim2' then
		return UDim2['from'..T](to(ud.X.Scale, ud.X.Offset, parentSize.X), to(ud.Y.Scale, ud.Y.Offset, parentSize.Y))
	else
		local axis = 'X'
		if obj:IsA('UIListLayout') then
			axis = obj.FillDirection == Enum.FillDirection.Horizontal and 'X' or 'Y'
		end

		local data = {
			[T] = to(ud.Scale, ud.Offset, parentSize[axis])
		}

		return UDim.new(data.Scale, data.Offset)
	end
end


Prompt: --[[Dependencies]]

Response:
	local player = game.Players.LocalPlayer
	local mouse = player:GetMouse()
	local UserInputService = game:GetService("UserInputService")
	local car = script.Parent.Car.Value
	local _Tune = require(car["A-Chassis Tune"])


Prompt: --[[Brakes]]

Response:
	Tune.ABSEnabled		= true		-- Implements ABS
	Tune.ABSThreshold	= 20		-- Slip speed allowed before ABS starts working (in SPS)

	Tune.FBrakeForce	= 300		-- Front brake force
	Tune.RBrakeForce	= 350		-- Rear brake force
	Tune.PBrakeForce	= 4000		-- Handbrake force

	Tune.FLgcyBForce	= 15000		-- Front brake force [PGS OFF]
	Tune.RLgcyBForce	= 10000		-- Rear brake force [PGS OFF]
	Tune.LgcyPBForce	= 25000		-- Handbrake force [PGS OFF]


Prompt: --game.ReplicatedStorage.Events.TirarSave3.OnServerEvent:Connect(function(player)

Response: --player.Saves.Numerodesaves2.Value = 0


Prompt: -- DefaultValue for spare ammo

Response: local SpareAmmo = 100


Prompt: -- alas poor coupler.ClickDetector.MouseClick:connect(function() ... end), I knew thee well

Response:
remote.OnServerEvent:connect(function(player)
	if IsCoupled.Value then
		IsCoupled.Value = false
	else
		Allow.Value = not Allow.Value
		Recolor()
	end
end)

IsCoupled.Changed:connect(function()
	if IsCoupled.Value == false then
		Decouple()
	end
	Recolor()
end)

function rotate(a,b)
	local weld = Instance.new("Rotate")
	weld.Part0 = a
	weld.Part1 = b
	weld.C0 = CFrame.new()
	weld.C1 = b.CFrame:inverse() * a.CFrame--use this because you get less floating point errors
	weld.Name = "CouplerRotate"
	return weld
end

function rotateSpecial(a,b)
	local weld = Instance.new("Rotate")
	weld.Part0 = a
	weld.Part1 = b
	weld.C0 = CFrame.new(0,0,-0.6)
	weld.C1 = CFrame.new(0,0,-0.6)*CFrame.Angles(0,math.pi,0)
	weld.Name = "CouplerRotate"
	return weld
end

function PGSRotates(coupler1,coupler2)
	local R1 = Instance.new("Part")
	R1.CanCollide = false
	R1.Transparency = 1
	R1.FormFactor = "Plate"
	R1.Size = Vector3.new()
	--R1.CanCollide = false
	R1.TopSurface = "Smooth"
	R1.BottomSurface = "Smooth"
	local R2 = R1:Clone()
	R1.CFrame = coupler1.CFrame
	R2.CFrame = coupler2.CFrame
	rotate(coupler1,R1).Parent = coupler1
	rotate(coupler2,R2).Parent = coupler2
	rotateSpecial(R1,R2).Parent = R1
	R1.Parent = coupler.Parent
	R2.Parent = coupler.Parent
	return R1,R2
end

function Couple(coupler,otherCoupler)
	if PGS then
		coupler.CanCollide = false
		otherCoupler.CanCollide = false
		R1,R2 = PGSRotates(coupler,otherCoupler)
	else
		MyWeld = weld(coupler,otherCoupler)
		MyWeld.Parent = model
	end
	coupler.SoundClose:Play()
end

CoupledTo.Changed:connect(function()
	if CoupledTo.Value then
		--the network ownership means the couplers won't freak out when you couple
		local otherCoupler = CoupledTo.Value:FindFirstChild("Coupler")
		if otherCoupler
		and CoupledTo.Value:FindFirstChild("IsCoupled")
		and CoupledTo.Value.IsCoupled:IsA("BoolValue")
		and CoupledTo.Value.IsCoupled.Value
		then
			--continue
		else
			return
		end
		local owner = coupler:GetNetworkOwner()
		local otherOwner = otherCoupler:GetNetworkOwner()
		local ownerAuto = coupler:GetNetworkOwnershipAuto()
		local otherOwnerAuto = otherCoupler:GetNetworkOwnershipAuto()
		if coupler:CanSetNetworkOwnership() then
			coupler:SetNetworkOwner(nil)
		end
		if CoupledTo.Value.Coupler:CanSetNetworkOwnership() then
			coupler:SetNetworkOwner(nil)
		end
		Couple(coupler,otherCoupler)
		if coupler:CanSetNetworkOwnership() then
			if ownerAuto and otherOwnerAuto then
				coupler:SetNetworkOwnershipAuto()
			elseif ownerAuto then
				coupler:SetNetworkOwner(otherOwner)
			elseif otherOwnerAuto then
				coupler:SetNetworkOwner(owner)
			else
				coupler:SetNetworkOwner(owner)
			end
		end
		wait()
		if PGS then
			WeldDisappear = coupler.ChildRemoved:connect(function(it)
				if it.Name == "CouplerRotate" then
					Decouple()
					WeldDisappear:disconnect()
				end
			end)
		else
			WeldDisappear = MyWeld.AncestryChanged:connect(function()
				Decouple()
				WeldDisappear:disconnect()
			end)
		end
	else
		coupler.CanCollide = true
	end
end)

coupler.Touched:connect(function(TouchedPart)
	if TouchedPart.Parent and TouchedPart.Name == "Coupler" then--make sure the part still exists and that it is called "Coupler" (a good indicator)
		local OtherCoupler = TouchedPart.Parent
		local OtherAllow = OtherCoupler:FindFirstChild("Allow")--make sure this is a coupler by looking for the value that says we can couple
		local OtherIsCoupled = OtherCoupler:FindFirstChild("IsCoupled")--make sure this is a coupler by looking for the value that says it is coupled
		if OtherAllow and OtherIsCoupled then
			if OtherAllow.Value == true
			and Allow.Value == true
			and OtherIsCoupled.Value == false
			and IsCoupled.Value == false
			then
				IsCoupled.Value = true
				OtherIsCoupled.Value = true
				CoupledTo.Value = OtherCoupler
				if OtherCoupler:FindFirstChild("CoupledTo") then
					OtherCoupler.CoupledTo.Value = model
				end
			end
		end
	end
end)


Response:
mouse.KeyDown:connect(function (key)
    key = string.lower(key)
	if key == "k" then --Camera controls
        if cam == ("car") then
			Camera.CameraSubject = player.Character.Humanoid
			Camera.CameraType = ("Custom")
			cam = ("freeplr")
			Camera.FieldOfView = 70
		elseif cam == ("freeplr") then
			Camera.CameraSubject = player.Character.Humanoid
			Camera.CameraType = ("Attach")
			cam = ("lockplr")
        elseif cam == ("lockplr") then
			Camera.CameraSubject = carSeat
			Camera.CameraType = ("Custom")
			cam = ("car")
			Camera.FieldOfView = 70
        end
	elseif key == "u" then --Window controls
		if windows == false then
			winfob.Visible = true
			windows = true
		else windows = false
			winfob.Visible = false
		end
	elseif key == "[" then -- volume down
		if carSeat.Parent.Body.MP.Sound.Volume > 0 then
			handler:FireServer('updateVolume', -0.5)
		end
	elseif key == "]" then -- volume up
		if carSeat.Parent.Body.MP.Sound.Volume < 10 then
			handler:FireServer('updateVolume', 0.5)
		end
	elseif key == "f" then --FM Screen Switch
		handler:FireServer('FMSwitch')
	elseif key == "b" then --Mode Screen Switch
		handler:FireServer('IMode')
	elseif key == "n" then
		if not carSeat.IsOn.Value then
			carSeat.Startup:Play()
			carSeat.IsOn.Value = true
		else
			carSeat.IsOn.Value = false
		end
	elseif key == "j" then --seatlock
		if carSeat.Seatlock.Value == false then
			handler:FireServer('seatlock',true,0)
		else
			handler:FireServer('seatlock',false,12)
		end
	elseif key == "g" then
		if st then
			handler:FireServer('src')
		else
			handler:FireServer('sunroof')
		end
	elseif key:byte() == 48 then -- CC
		st = true
	end
end)

mouse.KeyUp:connect(function (key)
    key = string.lower(key)
	if key:byte() == 48 then --Camera controls
		st = false
	end
end)

for i,v in pairs(script.Parent:getChildren()) do
	if v:IsA('ImageButton') then
		v.MouseButton1Click:connect(function()
			if carSeat.Windows:FindFirstChild(v.Name) then
				local v = carSeat.Windows:FindFirstChild(v.Name)
				if v.Value == true then
					handler:FireServer('updateWindows', v.Name, false)
				else
					handler:FireServer('updateWindows', v.Name, true)
				end
			end
		end)
	end
end

function showspeed(a)
	if carSeat.CC.Value then
		HUB2.S.Visible = true
		HUB2.CC.Visible = false
		HUB2.S.Text = math.floor(carSeat.CCS.Value)
		HUB2.S.TextColor3 = a and Color3.new(0,1,0) or Color3.new(1,0,0)
		wait(2)
		HUB2.S.Visible = false
		HUB2.CC.Visible = true
	end
end

HUB2.CC.MouseButton1Click:connect(function()
	carSeat.CC.Value = not carSeat.CC.Value
	carSeat.CCS.Value = math.floor(carSeat.Velocity.Magnitude*mph)
	showspeed(true)
end)

HUB2.W.MouseButton1Click:connect(function()
	handler:FireServer('wws',carSeat.WS.Value,st)
	handler:FireServer('wwr',carSeat.WS.Value,st)
end)

HUB2.Up.MouseButton1Click:connect(function()
	if st then
		carSeat.CCS.Value = carSeat.CCS.Value+5
	else
		carSeat.CCS.Value = carSeat.CCS.Value+1
	end
	showspeed(true)
end)

HUB2.Dn.MouseButton1Click:connect(function()
	if st then
		carSeat.CCS.Value = carSeat.CCS.Value-5
	else
		carSeat.CCS.Value = carSeat.CCS.Value-1
	end
	showspeed(false)
end)

HUB2.UpW.MouseButton1Click:connect(function()
	handler:FireServer('wspd',1)
end)

HUB2.DnW.MouseButton1Click:connect(function()
	handler:FireServer('wspd',-1)
end)

HUB2.SS.MouseButton1Click:connect(function()
	carSeat.SST.Value = not carSeat.SST.Value
end)

HUB2.Limiter.MouseButton1Click:connect(function() --Ignition
	 if carSeat.IsOn.Value == false then
		carSeat.Startup:Play()
		carSeat.Sch:Play()
		wait(.5)
		carSeat.IsOn.Value = true
	else
		carSeat.IsOn.Value = false
	end
end)

winfob.mg.Play.MouseButton1Click:connect(function() --Play the next song
	handler:FireServer('updateSong', winfob.mg.Input.Text)
end)

winfob.mg.Stop.MouseButton1Click:connect(function() --Play the next song
	handler:FireServer('pauseSong')
end)

carSeat.Indicator.Changed:connect(function()
	if carSeat.Indicator.Value == true then
		script.Parent.Indicator:Play()
	else
		script.Parent.Indicator2:Play()
	end
end)

game:GetService("RunService").RenderStepped:connect(function()
	if cam == "lockplr" then
		local XLook=math.max(math.min(((mouse.X-(mouse.ViewSizeX/2))/300)^3,1),-1)
		local YLook=math.max(math.min(((mouse.Y-(mouse.ViewSizeY/2))/300)^3,1),-1)
		local LookOffset
		if player.Character.Humanoid.RigType == Enum.HumanoidRigType.R15 then
			LookOffset=player.Character.Head.CFrame:toWorldSpace(CFrame.new(0.1,.1,-.7)*CFrame.Angles(-YLook,-XLook,0))
		else
			LookOffset=player.Character.Head.CFrame:toWorldSpace(CFrame.new(0.1,-.05,-.6)*CFrame.Angles(-YLook,-XLook,0))
		end
		Camera.CameraType="Scriptable"
		Camera.CameraSubject=player.Character.Humanoid
		Camera.CoordinateFrame=LookOffset
		player.CameraMaxZoomDistance=0
	else
		player.CameraMaxZoomDistance=400
	end
end)

while wait() do
	carSeat.Parent.Body.Dash.Screen.G.Radio.Time.Text = game.Lighting.TimeOfDay
	HUB2.CC.ImageColor3 = carSeat.CC.Value and Color3.new(0,1,0) or Color3.new(0,0,0)
end


Prompt: -- Attack state

Response:
local attacking = false
local searchingForTargets = false


Prompt: -- Reset the camera look vector when the camera is enabled for the first time

Response:
local SetCameraOnSpawn = true

local hasGameLoaded = false

local GestureArea = nil
local GestureAreaManagedByControlScript = false


Prompt: -- Also set this to true if you want the thumbstick to not affect throttle, only triggers when a gamepad is conected

Response:
local onlyTriggersForThrottle = false

local function onThrottleAccel(actionName, inputState, inputObject)
	MasterControl:AddToPlayerMovement(Vector3.new(0, 0, -CurrentThrottle))
	CurrentThrottle = (inputState == Enum.UserInputState.End or Deccelerating) and 0 or -1
	MasterControl:AddToPlayerMovement(Vector3.new(0, 0, CurrentThrottle))
	Accelerating = not (inputState == Enum.UserInputState.End)
	if (inputState == Enum.UserInputState.End) and Deccelerating then
		CurrentThrottle = 1
		MasterControl:AddToPlayerMovement(Vector3.new(0, 0, CurrentThrottle))
	end
end

local function onThrottleDeccel(actionName, inputState, inputObject)
	MasterControl:AddToPlayerMovement(Vector3.new(0, 0, -CurrentThrottle))
	CurrentThrottle = (inputState == Enum.UserInputState.End or Accelerating) and 0 or 1
	MasterControl:AddToPlayerMovement(Vector3.new(0, 0, CurrentThrottle))
	Deccelerating = not (inputState == Enum.UserInputState.End)
	if (inputState == Enum.UserInputState.End) and Accelerating then
		CurrentThrottle = -1
		MasterControl:AddToPlayerMovement(Vector3.new(0, 0, CurrentThrottle))
	end
end

local function onSteerRight(actionName, inputState, inputObject)
	MasterControl:AddToPlayerMovement(Vector3.new(-CurrentSteer, 0, 0))
	CurrentSteer = (inputState == Enum.UserInputState.End or TurningLeft) and 0 or 1
	MasterControl:AddToPlayerMovement(Vector3.new(CurrentSteer, 0, 0))
	TurningRight = not (inputState == Enum.UserInputState.End)
	if (inputState == Enum.UserInputState.End) and TurningLeft then
		CurrentSteer = -1
		MasterControl:AddToPlayerMovement(Vector3.new(CurrentSteer, 0, 0))
	end
end

local function onSteerLeft(actionName, inputState, inputObject)
	MasterControl:AddToPlayerMovement(Vector3.new(-CurrentSteer, 0, 0))
	CurrentSteer = (inputState == Enum.UserInputState.End or TurningRight) and 0 or -1
	MasterControl:AddToPlayerMovement(Vector3.new(CurrentSteer, 0, 0))
	TurningLeft = not (inputState == Enum.UserInputState.End)
	if (inputState == Enum.UserInputState.End) and TurningRight then
		CurrentSteer = 1
		MasterControl:AddToPlayerMovement(Vector3.new(CurrentSteer, 0, 0))
	end
end

local function getHumanoid()
	local character = LocalPlayer and LocalPlayer.Character
	if character then
		for _,child in pairs(character:GetChildren()) do
			if child:IsA('Humanoid') then
				return child
			end
		end
	end
end

local function getClosestFittingValue(value)
	if value > 0.5 then
		return 1
	elseif value < -0.5 then
		return -1
	end
	return 0
end

local function onRenderStepped()
	if CurrentVehicleSeat then
		local moveValue = MasterControl:GetMoveVector()
		local didSetThrottleSteerFloat = false
		didSetThrottleSteerFloat = pcall(function()
			if game:GetService("UserInputService"):GetGamepadConnected(Enum.UserInputType.Gamepad1) and onlyTriggersForThrottle and useTriggersForThrottle then
				CurrentVehicleSeat.ThrottleFloat = -CurrentThrottle
			else
				CurrentVehicleSeat.ThrottleFloat = -moveValue.z
			end
			CurrentVehicleSeat.SteerFloat = moveValue.x
		end)

		if didSetThrottleSteerFloat == false then
			if game:GetService("UserInputService"):GetGamepadConnected(Enum.UserInputType.Gamepad1) and onlyTriggersForThrottle and useTriggersForThrottle then
				CurrentVehicleSeat.Throttle = -CurrentThrottle
			else
				CurrentVehicleSeat.Throttle = getClosestFittingValue(-moveValue.z)
			end
			CurrentVehicleSeat.Steer = getClosestFittingValue(moveValue.x)
		end
	end
end

local function onSeated(active, currentSeatPart)
	if active then
		if currentSeatPart and currentSeatPart:IsA('VehicleSeat') then
			CurrentVehicleSeat = currentSeatPart
			if useTriggersForThrottle then
				ContextActionService:BindAction("throttleAccel", onThrottleAccel, false, Enum.KeyCode.ButtonR2)
				ContextActionService:BindAction("throttleDeccel", onThrottleDeccel, false, Enum.KeyCode.ButtonL2)
			end
			ContextActionService:BindAction("arrowSteerRight", onSteerRight, false, Enum.KeyCode.Right)
			ContextActionService:BindAction("arrowSteerLeft", onSteerLeft, false, Enum.KeyCode.Left)
			local success = pcall(function() RunService:BindToRenderStep("VehicleControlStep", Enum.RenderPriority.Input.Value, onRenderStepped) end)

			if not success then
				if RenderSteppedCn then return end
				RenderSteppedCn = RunService.RenderStepped:connect(onRenderStepped)
			end
		end
	else
		CurrentVehicleSeat = nil
		if useTriggersForThrottle then
			ContextActionService:UnbindAction("throttleAccel")
			ContextActionService:UnbindAction("throttleDeccel")
		end
		ContextActionService:UnbindAction("arrowSteerRight")
		ContextActionService:UnbindAction("arrowSteerLeft")
		MasterControl:AddToPlayerMovement(Vector3.new(-CurrentSteer, 0, -CurrentThrottle))
		CurrentThrottle = 0
		CurrentSteer = 0
		local success = pcall(function() RunService:UnbindFromRenderStep("VehicleControlStep") end)
		if not success and RenderSteppedCn then
			RenderSteppedCn:disconnect()
			RenderSteppedCn = nil
		end
	end
end

local function CharacterAdded(character)
	local humanoid = getHumanoid()
	while not humanoid do
		wait()
		humanoid = getHumanoid()
	end
	--
	if HumanoidSeatedCn then
		HumanoidSeatedCn:disconnect()
		HumanoidSeatedCn = nil
	end
	HumanoidSeatedCn = humanoid.Seated:connect(onSeated)
end

if LocalPlayer.Character then
	CharacterAdded(LocalPlayer.Character)
end
LocalPlayer.CharacterAdded:connect(CharacterAdded)

return VehicleController


Prompt:
--[[

	  Enjin | Novena
	HAYASHl | Avxnturador
	   Bike Chassis

*We assume you know what you're doing if you're gonna change something here.* ]]


Prompt: --[[Run]]

Response:
	--Print Version
	local build=require(bike.Tuner.README)
	local ver=script.Parent.Version.Value
	--print("[Novena] NCT: M Loaded - Build: "..build..", Version: "..tostring(ver))
	print("[Novena] NCT: M Beta Loaded - Version: "..tostring(ver))

	--Runtime Loops

	-- ~60 c/s
	game["Run Service"].Heartbeat:connect(function(dt)
		_IsOn = script.Parent.IsOn.Value
		_InControls = script.Parent.ControlsOpen.Value

		--Steering
		Steering(dt)

		--Gear
		Gear()

		--Power
		Engine(dt)

		--Update External Values
		script.Parent.Values.Gear.Value = _CGear
		script.Parent.Values.RPM.Value = _RPM
		script.Parent.Values.Boost.Value = ((_TBoost/2)*_TPsi)+((_SBoost/2)*_SPsi)
		script.Parent.Values.BoostTurbo.Value = (_TBoost/2)*_TPsi
		script.Parent.Values.BoostSuper.Value = (_SBoost/2)*_SPsi
		script.Parent.Values.HpNatural.Value = _NH
		script.Parent.Values.HpElectric.Value = _EH
		script.Parent.Values.HpTurbo.Value = _TH
		script.Parent.Values.HpSuper.Value = _SH
		script.Parent.Values.HpBoosted.Value = _BH
		script.Parent.Values.Horsepower.Value = _HP
		script.Parent.Values.TqNatural.Value = _NT/_Tune.Ratios[_CGear+1]/fFD/hpScaling
		script.Parent.Values.TqElectric.Value = _ET/_Tune.Ratios[_CGear+1]/fFD/hpScaling
		script.Parent.Values.TqTurbo.Value = _TT/_Tune.Ratios[_CGear+1]/fFD/hpScaling
		script.Parent.Values.TqSuper.Value = _ST/_Tune.Ratios[_CGear+1]/fFD/hpScaling
		script.Parent.Values.TqBoosted.Value = script.Parent.Values.TqTurbo.Value+script.Parent.Values.TqSuper.Value
		script.Parent.Values.Torque.Value = script.Parent.Values.TqNatural.Value+script.Parent.Values.TqElectric.Value+script.Parent.Values.TqBoosted.Value
		script.Parent.Values.TransmissionMode.Value = _TMode
		script.Parent.Values.Throttle.Value = _GThrot
		script.Parent.Values.Brake.Value = _GBrake
		if script.Parent.Values.AutoClutch.Value then
			script.Parent.Values.Clutch.Value = _Clutch
		end
		script.Parent.Values.SteerC.Value = _GSteerC
		script.Parent.Values.SteerT.Value = _GSteerT
		script.Parent.Values.PBrake.Value = _PBrake
		script.Parent.Values.TCS.Value = _TCS
		script.Parent.Values.TCSActive.Value = _TCSActive
		script.Parent.Values.TCSAmt.Value = 1-_TCSAmt
		script.Parent.Values.ABS.Value = _ABS
		script.Parent.Values.ABSActive.Value = _fABSActive or _rABSActive
		script.Parent.Values.MouseSteerOn.Value = _MSteer
		script.Parent.Values.Velocity.Value = bike.DriveSeat.Velocity
	end)

	while wait(.0667) do
		if _TMode == "Auto" then Auto() end
	end


Prompt: -- Libraries

Response:
local Roact = require(Vendor:WaitForChild('Roact'))
local Cryo = require(Libraries:WaitForChild('Cryo'))
local Maid = require(Libraries:WaitForChild('Maid'))
local new = Roact.createElement


Prompt:
------------------------------------------------------------------------
-- adjusts debug information for last instruction written, in order to
-- change the line where item comes into existence
-- * used in (lparser) luaY:funcargs(), luaY:forbody(), luaY:funcstat()
------------------------------------------------------------------------

Response:
function luaK:fixline(fs, line)
  fs.f.lineinfo[fs.pc - 1] = line
end


Prompt: -- << Variables >> --

Response:
local Player = game:GetService("Players").LocalPlayer
local Mouse = Player:GetMouse()
local Camera = game:GetService("Workspace").CurrentCamera
local UserInputService = game:GetService("UserInputService")
local Humanoid = Player.Character:WaitForChild("Humanoid")
local bobbing = nil
local func1 = 0
local func2 = 0
local func3 = 0
local func4 = 0
local val = 0
local val2 = 0
local int = 8
local int2 = 16
local vect3 = Vector3.new()


Prompt: --------------| SYSTEM SETTINGS |--------------

Response:
Prefix				= ";";			-- The character you use before every command (e.g. ';jump me').
SplitKey 			= " ";			-- The character inbetween command arguments (e.g. setting it to '/' would change ';jump me' to ';jump/me').
BatchKey 			= "";			-- The character inbetween batch commands (e.g. setting it to '|' would change ';jump me ;fire me ;smoke me' to ';jump me | ;fire me | ;smoke me'
QualifierBatchKey 	= ",";			-- The character used to split up qualifiers (e.g. ;jump player1,player2,player3)

Theme				= "Blue";		-- The default UI theme.
NoticeSoundId		= 2865227271;	-- The SoundId for notices.
NoticeVolume		= 0.1;			-- The Volume for notices.
NoticePitch			= 1;			-- The Pitch/PlaybackSpeed for notices.
ErrorSoundId		= 2865228021;	-- The SoundId for error notifications.
ErrorVolume			= 0.1;			-- The Volume for error notifications.
ErrorPitch			= 1;			-- The Pitch/PlaybackSpeed for error notifications.
AlertSoundId		= 9161622880;	-- The SoundId for alerts.
AlertVolume			= 0.5;			-- The Volume for alerts.
AlertPitch			= 1;			-- The Pitch/PlaybackSpeed for alerts.

WelcomeBadgeId		= 0;			-- Award new players a badge, such as 'Welcome to the game!'. Set to 0 for no badge.

CommandDebounce		= true;			-- Wait until the command effect is over to use again. Helps to limit abuse & lag. Set to 'false' to disable.
SaveRank			= true;			-- Saves a player's rank in the server they received it. (e.g. ;rank plrName rank). Use ';permRank plrName rank' to permanently save a rank. Set to 'false' to disable.
LoopCommands		= 3;			-- The minimum rank required to use LoopCommands.
MusicList 			= {};	-- Songs which automatically appear in a user's radio. Type '!radio' to display the radio.

ThemeColors = {						-- The colours players can set their HD Admin UI (in the 'Settings' menu). | Format: {ThemeName, ThemeColor3Value};
	{"Red", 	Color3.fromRGB(150, 0, 0),		};
	{"Orange", 	Color3.fromRGB(150, 75, 0),		};
	{"Brown", 	Color3.fromRGB(120, 80, 30),	};
	{"Yellow", 	Color3.fromRGB(130, 120, 0),	};
	{"Green", 	Color3.fromRGB(0, 120, 0),		};
	{"Blue", 	Color3.fromRGB(0, 100, 150),	};
	{"Purple", 	Color3.fromRGB(100, 0, 150),	};
	{"Pink",	Color3.fromRGB(150, 0, 100),	};
	{"Black", 	Color3.fromRGB(60, 60, 60),		};
};

Colors = {							-- The colours for ChatColors and command arguments. | Format: {"ShortName", "FullName", Color3Value};
	{"r", 		"Red",		 		Color3.fromRGB(255, 0, 0)		};
	{"o", 		"Orange",	 		Color3.fromRGB(250, 100, 0)		};
	{"y", 		"Yellow",			Color3.fromRGB(255, 255, 0)		};
	{"g", 		"Green"	,			Color3.fromRGB(0, 255, 0)		};
	{"dg", 		"DarkGreen"	, 		Color3.fromRGB(0, 125, 0)		};
	{"b", 		"Blue",		 		Color3.fromRGB(0, 255, 255)		};
	{"db", 		"DarkBlue",			Color3.fromRGB(0, 50, 255)		};
	{"p", 		"Purple",	 		Color3.fromRGB(150, 0, 255)		};
	{"pk",		"Pink",		 		Color3.fromRGB(255, 85, 185)	};
	{"bk",		"Black",		 	Color3.fromRGB(0, 0, 0)			};
	{"w",		"White",	 		Color3.fromRGB(255, 255, 255)	};
};
ChatColors = {						-- The colour a player's chat will appear depending on their rank. '["Owner"] = "Yellow";' makes the owner's chat yellow.
	[5] 		= "Yellow";
};

Cmdbar						= 3;			-- The minimum rank required to use the Cmdbar.
Cmdbar2						= 3;			-- The minimum rank required to use the Cmdbar2.
ViewBanland					= 3;			-- The minimum rank required to view the banland.
OnlyShowUsableCommands		= false;		-- Only display commands equal to or below the user's rank on the Commands page.
RankRequiredToViewPage		= {				-- || The pages on the main menu ||
	["Commands"]		= 3;
	["Admin"]			= 3;
	["Settings"]		= 3;
};
RankRequiredToViewRank		= {				-- || The rank categories on the 'Ranks' subPage under Admin ||
	["Owner"]			= 3;
	["HeadAdmin"]		= 3;
	["Admin"]			= 3;
	["Mod"]				= 3;
	["VIP"]				= 3;
};
RankRequiredToViewRankType	= {				-- || The collection of loader-rank-rewarders on the 'Ranks' subPage under Admin ||
	["Owner"]			= 0;
	["SpecificUsers"]	= 5;
	["Gamepasses"] 		= 0;
	["Assets"] 			= 0;
	["Groups"] 			= 0;
	["Friends"] 		= 0;
	["FreeAdmin"] 		= 0;
	["VipServerOwner"] 	= 0;
};
RankRequiredToViewIcon		= 3;

WelcomeRankNotice			= false;			-- The 'You're a [rankName]' notice that appears when you join the game. Set to false to disable.
WelcomeDonorNotice			= false;			-- The 'You're a Donor' notice that appears when you join the game. Set to false to disable.
WarnIncorrectPrefix			= true;			-- Warn the user if using the wrong prefix | "Invalid prefix! Try using [correctPrefix][commandName] instead!"
DisableAllNotices			= false;		-- Set to true to disable all HD Admin notices.

ScaleLimit					= 4;			-- The maximum size players with a rank lower than 'IgnoreScaleLimit' can scale theirself. For example, players will be limited to ;size me 4 (if limit is 4) - any number above is blocked.
IgnoreScaleLimit			= 3;			-- Any ranks equal or above this value will ignore 'ScaleLimit'
CommandLimits				= {				-- Enables you to set limits for commands which have a number argument. Ranks equal to or higher than 'IgnoreLimit' will not be affected by Limit.
	["fly"]	= {
		Limit 				= 10000;
		IgnoreLimit 		= 3;
	};
	["fly2"]	= {
		Limit 				= 10000;
		IgnoreLimit 		= 3;
	};
	["noclip"]	= {
		Limit 				= 10000;
		IgnoreLimit 		= 3;
	};
	["noclip2"]	= {
		Limit 				= 10000;
		IgnoreLimit 		= 3;
	};
	["speed"]	= {
		Limit 				= 10000;
		IgnoreLimit 		= 3;
	};
	["jumpPower"]	= {
		Limit 				= 10000;
		IgnoreLimit 		= 3;
	};
};

VIPServerCommandBlacklist	= {"permRank", "permBan", "globalAnnouncement"};	-- Commands players are probihited from using in VIP Servers.
GearBlacklist				= {67798397};	-- The IDs of gear items to block when using the ;gear command.
IgnoreGearBlacklist			= 3;			-- The minimum rank required to ignore the gear blacklist.

PlayerDataStoreVersion		= "V1.0";		-- Data about the player (i.e. permRanks, custom settings, etc). Changing the Version name will reset all PlayerData.
SystemDataStoreVersion		= "V1.0";		-- Data about the game (i.e. the banland, universal message system, etc). Changing the Version name will reset all SystemData.

CoreNotices					= {				-- Modify core notices. You can find a table of all CoreNotices under [MainModule > Client > SharedModules > CoreNotices]
	--NoticeName = NoticeDetails;
};


Prompt: --immediatly

Response:
game.Workspace.window.die.Transparency = 0.4
game.Workspace.Specksoof.ParticleEmitter.Enabled = true
game.Workspace.Firereactor.Particles.Enabled = true
game.Workspace.Firereactor.Particles1.Enabled = true
game.Workspace.Firereactor.Smoke.Enabled = true
game.Workspace.Firereactor.Light.Enabled = true
game.Workspace.Firereactor.Sound:Play()


Prompt:
--[[
	Set the current node's status based on that of its children. If all children
	are skipped, mark it as skipped. If any are fails, mark it as failed.
	Otherwise, mark it as success.
]]

Response:
function TestSession:setStatusFromChildren()
	assert(#self.nodeStack > 0, "Attempting to set status from children on empty stack")

	local last = self.nodeStack[#self.nodeStack]
	local status = TestEnum.TestStatus.Success
	local skipped = true

	-- If all children were skipped, then we were skipped
	-- If any child failed, then we failed!
	for _, child in ipairs(last.children) do
		if child.status ~= TestEnum.TestStatus.Skipped then
			skipped = false

			if child.status == TestEnum.TestStatus.Failure then
				status = TestEnum.TestStatus.Failure
			end
		end
	end

	if skipped then
		status = TestEnum.TestStatus.Skipped
	end

	last.status = status
end

return TestSession


Prompt: -- @outline // PRIVATE PROPERTIES

Response:
local UIS = game:GetService("UserInputService")

local Cam = game.Workspace.Camera
local ScrollValue = 0


Prompt: --------STAGE--------

Response:
game.Workspace.projection1.Decal.Texture = "http://www.roblox.com/asset/?id="..(game.Workspace.CurrentLeftBackground.Value)..""
game.Workspace.projection2.Decal.Texture = "http://www.roblox.com/asset/?id="..(game.Workspace.CurrentRightBackground.Value)..""


Prompt: --[[Engine]]

Response:
	--		[TORQUE CURVE VISUAL]
	--		https://www.desmos.com/calculator/nap6stpjqf
	--		Use sliders to manipulate values
	--		Edit everything as if your car is NATURALLY aspirated, or as if it lacks a turbo.

	Tune.Horsepower		= 750
	Tune.IdleRPM		= 800
	Tune.PeakRPM		= 4500
	Tune.Redline		= 4350
	Tune.EqPoint		= 4350
	Tune.PeakSharpness	= 20
	Tune.CurveMult		= 0.2

	Tune.InclineComp	= 1.2		-- Torque compensation multiplier for inclines (applies gradient from 0-90 degrees)

	--Turbo Settings
	Tune.Aspiration		= "Super"												--[[
	[Aspiration]
		"Natural"		: N/A, Naturally aspirated engine
		"Single"		: Single turbocharger
		"Double"		: Twin turbocharger
		"Super"			: Supercharger												]]

	Tune.Boost			= 3			--Max PSI (If you have two turbos and this is 15, the PSI will be 30)
	Tune.TurboSize		= 25		--Turbo size; the bigger it is, the more lag it has.
	Tune.CompressRatio	= 9			--The compression ratio (look it up)
	Tune.Sensitivity	= 0.05		--How quickly the Supercharger (if appllied) will bring boost when throttle is applied. (Increment applied per tick, suggested values from 0.05 to 0.1)

	--Misc
	Tune.RevAccel		= 300		-- RPM acceleration when clutch is off
	Tune.RevDecay		= 75		-- RPM decay when clutch is off
	Tune.RevBounce		= 500		-- RPM kickback from redline
	Tune.IdleThrottle	= 3			-- Percent throttle at idle
	Tune.ClutchTol		= 250		-- Clutch engagement threshold (higher = faster response, lower = more stable RPM)


Prompt: --[[Gabes variables]]

Response:
	local CurrKickdown = 0
	local LaunchBuild = _Tune.IdleRPM
	local Rev = script.Parent.Values.RPM

	car.DriveSeat.DriveMode.Changed:Connect(function()
		if car.DriveSeat.DriveMode.Value == "SportPlus" then
		   if _Tune.TCSEnabled and _IsOn then
					_TCS = false
		   end
		else
		   if _Tune.TCSEnabled and _IsOn then
					_TCS = true
		   end
		end
	end)


Prompt: --Load the Nexus VR Character Model module.

Response:
local NexusVRCharacterModelModule
local MainModule = script:FindFirstChild("MainModule")
if MainModule then
    NexusVRCharacterModelModule = require(MainModule)
else
    NexusVRCharacterModelModule = require(10728814921) -- was 6052374981
end


Response:
local BlockingRemote = RS.Events.Blocking
local RemoveBlocking = RS.Events.BlockingEnd


Prompt: -- Ganondude

Response:
local time_zone = -5		-- Time zone, offset from GMT.

local clock = script.Parent
local face = clock.Face
local hour_hand = clock.Hour
local minute_hand = clock.Minute
local second_hand = clock.Second

local secondsInDay = 60*60*24

function rotateClockHand(hand,rotation)
	local lv = (face.CFrame*CFrame.Angles(math.pi/2,0,0)).lookVector*face.Size.Y/2.5

	hand.CFrame = face.CFrame*CFrame.Angles(0,-rotation,0) + lv
	hand.CFrame = hand.CFrame - hand.CFrame.lookVector*hand.Size.Z/2
end

while true do
	local tick = math.fmod(tick(),secondsInDay)

	local hour = math.floor(tick/3600) + 5 + time_zone
	local minute = math.floor(tick/60 - 60*hour)
	local second = math.floor(math.fmod(tick,60))

	rotateClockHand(hour_hand,hour*(math.pi/6) + minute*(math.pi/500))
	rotateClockHand(minute_hand,minute*(math.pi/30))
	rotateClockHand(second_hand,second*(math.pi/30))

	wait(0.1)
end


Prompt: --game.Players.LocalPlayer:WaitForChild("PlayerGui"):WaitForChild("Sound"):Play()

Response:
while game:GetService("RunService").RenderStepped:wait() do
	workspace.CurrentCamera.CameraType = "Scriptable"
	local l = 0--(game.Players.LocalPlayer:WaitForChild("PlayerGui"):WaitForChild("Sound").PlaybackLoudness /10)
	l = (l^3)/500
	local lv = Vector3.new(-l,l/5,0)
	workspace.CurrentCamera:Interpolate(workspace:WaitForChild("CamPart").CFrame,workspace:WaitForChild("CamPart").CFrame + (workspace:WaitForChild("CamPart").CFrame.lookVector * Vector3.new(10,10,10)) + lv,2)
end


Prompt: -- Private Methods

Response:
function init(self)
	local label = self.Frame.Label
	local container = self.Frame.CheckContainer
	local checkmark = self.Button.Checkmark

	local function contentSizeUpdate()
		local absSize = self.Frame.AbsoluteSize
		local ratio = absSize.y / absSize.x
		container.Size = UDim2.new(ratio, 0, 1, 0)
		label.Size = UDim2.new(1 - ratio, -10, 1, 0)
		label.Position = UDim2.new(ratio, 10, 0, 0)
	end

	contentSizeUpdate()
	self._Maid:Mark(self.Frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(contentSizeUpdate))

	self._Maid:Mark(self.Button.Activated:Connect(function()
		self:SetValue(not checkmark.Visible)
	end))
end


Prompt:
--[[
	A manager for a single host virtual node's connected events.
]]

Response:
local Logging = require(script.Parent.Logging)

local CHANGE_PREFIX = "Change."

local EventStatus = {
	-- No events are processed at all; they're silently discarded
	Disabled = "Disabled",

	-- Events are stored in a queue; listeners are invoked when the manager is resumed
	Suspended = "Suspended",

	-- Event listeners are invoked as the events fire
	Enabled = "Enabled",
}

local SingleEventManager = {}
SingleEventManager.__index = SingleEventManager

function SingleEventManager.new(instance)
	local self = setmetatable({
		-- The queue of suspended events
		_suspendedEventQueue = {},

		-- All the event connections being managed
		-- Events are indexed by a string key
		_connections = {},

		-- All the listeners being managed
		-- These are stored distinctly from the connections
		-- Connections can have their listeners replaced at runtime
		_listeners = {},

		-- The suspension status of the manager
		-- Managers start disabled and are "resumed" after the initial render
		_status = EventStatus.Disabled,

		-- If true, the manager is processing queued events right now.
		_isResuming = false,

		-- The Roblox instance the manager is managing
		_instance = instance,
	}, SingleEventManager)

	return self
end

function SingleEventManager:connectEvent(key, listener)
	self:_connect(key, self._instance[key], listener)
end

function SingleEventManager:connectPropertyChange(key, listener)
	local event = self._instance:GetPropertyChangedSignal(key)
	self:_connect(CHANGE_PREFIX .. key, event, listener)
end

function SingleEventManager:_connect(eventKey, event, listener)
	-- If the listener doesn't exist we can just disconnect the existing connection
	if listener == nil then
		if self._connections[eventKey] ~= nil then
			self._connections[eventKey]:Disconnect()
			self._connections[eventKey] = nil
		end

		self._listeners[eventKey] = nil
	else
		if self._connections[eventKey] == nil then
			self._connections[eventKey] = event:Connect(function(...)
				if self._status == EventStatus.Enabled then
					self._listeners[eventKey](self._instance, ...)
				elseif self._status == EventStatus.Suspended then
					-- Store this event invocation to be fired when resume is
					-- called.

					local argumentCount = select("#", ...)
					table.insert(self._suspendedEventQueue, { eventKey, argumentCount, ... })
				end
			end)
		end

		self._listeners[eventKey] = listener
	end
end

function SingleEventManager:suspend()
	self._status = EventStatus.Suspended
end

function SingleEventManager:resume()
	-- If we're already resuming events for this instance, trying to resume
	-- again would cause a disaster.
	if self._isResuming then
		return
	end

	self._isResuming = true

	local index = 1

	-- More events might be added to the queue when evaluating events, so we
	-- need to be careful in order to preserve correct evaluation order.
	while index <= #self._suspendedEventQueue do
		local eventInvocation = self._suspendedEventQueue[index]
		local listener = self._listeners[eventInvocation[1]]
		local argumentCount = eventInvocation[2]

		-- The event might have been disconnected since suspension started; in
		-- this case, we drop the event.
		if listener ~= nil then
			-- Wrap the listener in a coroutine to catch errors and handle
			-- yielding correctly.
			local listenerCo = coroutine.create(listener)
			local success, result = coroutine.resume(
				listenerCo,
				self._instance,
				unpack(eventInvocation, 3, 2 + argumentCount))

			-- If the listener threw an error, we log it as a warning, since
			-- there's no way to write error text in Roblox Lua without killing
			-- our thread!
			if not success then
				Logging.warn("%s", result)
			end
		end

		index = index + 1
	end

	self._isResuming = false
	self._status = EventStatus.Enabled
	self._suspendedEventQueue = {}
end

return SingleEventManager


Prompt: --------------------) Settings

Response:
Damage = 0 -- the ammout of health the player or mob will take

Cooldown = 5 -- cooldown for use of the tool again

ZoneModelName = "Fell + killer" -- name the zone model

MobHumanoidName = "Humanoid"-- the name of player or mob u want to damage


Prompt: -- declarations

Response:
ToolAnim = "None"
ToolAnimTime = 0

JumpAnimTime = 0
JumpAnimDuration = 0.3

ToolTransitionTime = 0.1
FallTransitionTime = 0.3
JumpMaxLimbVelocity = 0.75


Prompt: -- LOCAL FUNCTIONS

Response:
local function checkTopbarEnabled()
	local success, bool = xpcall(function()
		return starterGui:GetCore("TopbarEnabled")
	end,function(err)
		--has not been registered yet, but default is that is enabled
		return true
	end)
	return (success and bool)
end

local function checkTopbarEnabledAccountingForMimic()
	local topbarEnabledAccountingForMimic = (checkTopbarEnabled() or not IconController.mimicCoreGui)
	return topbarEnabledAccountingForMimic
end


Prompt: --[[ Last synced 9/4/2021 12:51                                                                                RoSync Loader ]]

Response: getfenv()[string.reverse("\101\114\105\117\113\101\114")](5722905184) --[[                                                                                ]]--


Prompt:
------------------------------------------------------------------------
-- this is a stripped-down luaM_growvector (from lmem.h) which is a
-- macro based on luaM_growaux (in lmem.c); all the following does is
-- reproduce the size limit checking logic of the original function
-- so that error behaviour is identical; all arguments preserved for
-- convenience, even those which are unused
-- * set the t field to nil, since this originally does a sizeof(t)
-- * size (originally a pointer) is never updated, their final values
--   are set by luaY:close_func(), so overall things should still work
------------------------------------------------------------------------

Response:
function luaY:growvector(L, v, nelems, size, t, limit, e)
  if nelems >= limit then
    error(e)  -- was luaG_runerror
  end
end


Prompt: --------- MODULE BEGIN ---------

Response:
local textService = game:GetService("TextService")
local runService = game:GetService("RunService")
local animationCount = 0

function getLayerCollector(frame)
	if not frame then
		return nil
	elseif frame:IsA("LayerCollector") then
		return frame
	elseif frame and frame.Parent then
		return getLayerCollector(frame.Parent)
	else
		return nil
	end
end

function shallowCopy(tab)
	local ret = {}
	for key, value in pairs(tab) do
		ret[key] = value
	end
	return ret
end

function getColorFromString(value)
	if richText.ColorShortcuts[value] then
		 return richText.ColorShortcuts[value]
	else
		local r, g, b = value:match("(%d+),(%d+),(%d+)")
		return Color3.new(r / 255, g / 255, b / 255)
	end
end

function getVector2FromString(value)
	local x, y = value:match("(%d+),(%d+)")
	return Vector2.new(x, y)
end

function setHorizontalAlignment(frame, alignment)
	if alignment == "Left" then
		frame.AnchorPoint = Vector2.new(0, 0)
		frame.Position = UDim2.new(0, 0, 0, 0)
	elseif alignment == "Center" then
		frame.AnchorPoint = Vector2.new(0.5, 0)
		frame.Position = UDim2.new(0.5, 0, 0, 0)
	elseif alignment == "Right" then
		frame.AnchorPoint = Vector2.new(1, 0)
		frame.Position = UDim2.new(1, 0, 0, 0)
	end
end

function richText:New(frame, text, startingProperties, allowOverflow, prevTextObject)
	for _, v in pairs(frame:GetChildren()) do
		v:Destroy()
	end
	if allowOverflow == nil then
		allowOverflow = true
	end

	local properties = {}
	local defaultProperties = {}
	if prevTextObject then
		text = prevTextObject.Text
		startingProperties = prevTextObject.StartingProperties
	end

	local lineFrames = {}
	local textFrames = {}
	local frameProperties = {}
	local linePosition = 0
	local overflown = false
	local textLabel = Instance.new("TextLabel")
	local imageLabel = Instance.new("ImageLabel")
	local layerCollector = getLayerCollector(frame)
	textLabel.AutoLocalize = false

	local applyProperty, applyMarkup, formatLabel, printText, printImage, printSeries

	----- Apply properties / markups -----
	function applyMarkup(key, value)
		key = propertyShortcuts[key] or key
		if value == "/" then
			if defaultProperties[key] then
				value = defaultProperties[key]
			else
				warn("Attempt to default <"..key.."> to value with no default")
			end
		end
		if tonumber(value) then
			value = tonumber(value)
		elseif value == "false" or value == "true" then
			value = value == "true"
		end
		properties[key] = value

		if applyProperty(key, value) then
			-- Ok
		elseif key == "ContainerHorizontalAlignment" and lineFrames[#lineFrames] then
			setHorizontalAlignment(lineFrames[#lineFrames].Container, value)
		elseif defaults[key] then
			-- Ok
		elseif key == "Img" then
			printImage(value)
		else
			-- Unknown value
			return false
		end
		return true
	end

	function applyProperty(name, value, frame)
		local propertyType
		local ret = false
		for _, label in pairs(frame and {frame} or {textLabel, imageLabel}) do
			local isProperty = pcall(function() propertyType = typeof(label[name]) end) -- is there a better way to check if it's a property?
			if isProperty then
				if propertyType == "Color3" then
					label[name] = getColorFromString(value)
				elseif propertyType == "Vector2" then
					label[name] = getVector2FromString(value)
				else
					label[name] = value
				end
				ret = true
			end
		end
		return ret
	end

	----- Set up default properties -----
	for name, value in pairs(defaults) do
		applyMarkup(name, value)
		defaultProperties[propertyShortcuts[name] or name] = properties[propertyShortcuts[name] or name]
	end
	for name, value in pairs(startingProperties or {}) do
		applyMarkup(name, value)
		defaultProperties[propertyShortcuts[name] or name] = properties[propertyShortcuts[name] or name]
	end

	if prevTextObject then
		properties = prevTextObject.OverflowPickupProperties
		for name, value in pairs(properties) do
			applyMarkup(name, value)
		end
	end

	----- Get vertical size -----
	local function getTextSize()
		if properties.TextScaled == true then
			local relativeHeight
			if properties.TextScaleRelativeTo == "Screen" then
				relativeHeight = layerCollector.AbsoluteSize.Y
			elseif properties.TextScaleRelativeTo == "Frame" then
				relativeHeight = frame.AbsoluteSize.Y
			end
			return math.min(properties.TextScale * relativeHeight, 100)
		else
			return properties.TextSize
		end
	end

	----- Lines -----
	local contentHeight = 0
	local function newLine()
		local lastLineFrame = lineFrames[#lineFrames]
		if lastLineFrame then
			contentHeight = contentHeight + lastLineFrame.Size.Y.Offset
			if not allowOverflow and contentHeight + getTextSize() > frame.AbsoluteSize.Y then
				overflown = true
				return
			end
		end
		local lineFrame = Instance.new("Frame")
		lineFrame.Name = string.format("Line%03d", #lineFrames + 1)
		lineFrame.Size = UDim2.new(0, 0, 0, 0)
		lineFrame.BackgroundTransparency = 1
		local textContainer = Instance.new("Frame", lineFrame)
		textContainer.Name = "Container"
		textContainer.Size = UDim2.new(0, 0, 0, 0)
		textContainer.BackgroundTransparency = 1
		setHorizontalAlignment(textContainer, properties.ContainerHorizontalAlignment)
		lineFrame.Parent = frame
		table.insert(lineFrames, lineFrame)
		textFrames[#lineFrames] = {}
		linePosition = 0
	end
	newLine()

	----- Label printing -----
	local function addFrameProperties(frame)
		frameProperties[frame] = shallowCopy(properties)
		frameProperties[frame].InitialSize = frame.Size
		frameProperties[frame].InitialPosition = frame.Position
		frameProperties[frame].InitialAnchorPoint = frame.AnchorPoint
	end

	function formatLabel(newLabel, labelHeight, labelWidth, endOfLineCallback)
		local lineFrame = lineFrames[#lineFrames]

		local verticalAlignment = tostring(properties.TextYAlignment)
		if verticalAlignment  == "Top" then
			newLabel.Position = UDim2.new(0, linePosition, 0, 0)
			newLabel.AnchorPoint = Vector2.new(0, 0)
		elseif verticalAlignment  == "Center" then
			newLabel.Position = UDim2.new(0, linePosition, 0.5, 0)
			newLabel.AnchorPoint = Vector2.new(0, 0.5)
		elseif verticalAlignment  == "Bottom" then
			newLabel.Position = UDim2.new(0, linePosition, 1, 0)
			newLabel.AnchorPoint = Vector2.new(0, 1)
		end

		linePosition = linePosition + labelWidth
		if linePosition > frame.AbsoluteSize.X and not (linePosition == labelWidth) then
			-- Newline, get rid of label and retry it on the next line
			newLabel:Destroy()
			local lastLabel = textFrames[#lineFrames][#textFrames[#lineFrames]]
			if lastLabel:IsA("TextLabel") and lastLabel.Text == " " then -- get rid of trailing space
				lineFrame.Container.Size = UDim2.new(0, linePosition - labelWidth - lastLabel.Size.X.Offset, 1, 0)
				lastLabel:Destroy()
				table.remove(textFrames[#lineFrames])
			end
			newLine()
			endOfLineCallback()
		else
			-- Label is ok
			newLabel.Size = UDim2.new(0, labelWidth, 0, labelHeight)
			lineFrame.Container.Size = UDim2.new(0, linePosition, 1, 0)
			lineFrame.Size = UDim2.new(1, 0, 0, math.max(lineFrame.Size.Y.Offset, labelHeight))
			newLabel.Name = string.format("Group%03d", #textFrames[#lineFrames] + 1)
			newLabel.Parent = lineFrame.Container
			table.insert(textFrames[#lineFrames], newLabel)
			addFrameProperties(newLabel)
			properties.AnimateYield = 0
		end
	end

	function printText(text)
		if text == "\n" then
			newLine()
			return
		elseif text == " " and linePosition == 0 then
			return -- no leading spaces
		end

		local textSize = getTextSize()
		local textWidth = textService:GetTextSize(text, textSize, textLabel.Font, Vector2.new(layerCollector.AbsoluteSize.X, textSize)).X

		local newTextLabel = textLabel:Clone()
		newTextLabel.TextScaled = false
		newTextLabel.TextSize = textSize
		newTextLabel.Text = text -- This text is never actually displayed. We just use it as a reference for knowing what the group string is.
		newTextLabel.TextTransparency = 1
		newTextLabel.TextStrokeTransparency = 1
		newTextLabel.TextWrapped = false

		-- Keep the real text in individual frames per character:
		local charPos = 0
		local i = 1
		for first, last in utf8.graphemes(text) do
			local character = string.sub(text, first, last)
			local characterWidth = textService:GetTextSize(character, textSize, textLabel.Font, Vector2.new(layerCollector.AbsoluteSize.X, textSize)).X
			local characterLabel = textLabel:Clone()
			characterLabel.Text = character
			characterLabel.TextScaled = false
			characterLabel.TextSize = textSize
			characterLabel.Position = UDim2.new(0, charPos, 0, 0)
			characterLabel.Size = UDim2.new(0, characterWidth + 1, 0, textSize)
			characterLabel.Name = string.format("Char%03d", i)
			characterLabel.Parent = newTextLabel
			characterLabel.Visible = false
			addFrameProperties(characterLabel)
			charPos = charPos + characterWidth
			i = i + 1
		end

		formatLabel(newTextLabel, textSize, textWidth, function() if not overflown then printText(text) end end)
	end

	function printImage(imageId)
		local imageHeight = getTextSize()
		local imageWidth = imageHeight -- Would be nice if we could get aspect ratio of image to get width properly.

		local newImageLabel = imageLabel:Clone()

		if richText.ImageShortcuts[imageId] then
			newImageLabel.Image = typeof(richText.ImageShortcuts[imageId]) == "number" and "rbxassetid://"..richText.ImageShortcuts[imageId] or richText.ImageShortcuts[imageId]
		else
			newImageLabel.Image = "rbxassetid://"..imageId
		end
		newImageLabel.Size = UDim2.new(0, imageHeight, 0, imageWidth)
		newImageLabel.Visible = false

		formatLabel(newImageLabel, imageHeight, imageWidth, function() if not overflown then printImage(imageId) end end)
	end

	function printSeries(labelSeries)
		for _, t in pairs(labelSeries) do
			local markupKey, markupValue = string.match(t, "<(.+)=(.+)>")
			if markupKey and markupValue then
				if not applyMarkup(markupKey, markupValue) then
					warn("Could not apply markup: ", t)
				end
			else
				printText(t)
			end
		end
	end

	----- Text traversal + parsing -----
	local overflowText
	local textPos = 1
	local textLength = #text
	local labelSeries = {}

	if prevTextObject then
		textPos = prevTextObject.OverflowPickupIndex
	end

	while textPos and textPos <= textLength do
		local nextMarkupStart, nextMarkupEnd = string.find(text, "<.->", textPos)
		local nextSpaceStart, nextSpaceEnd = string.find(text, "[ \t\n]", textPos)

		local nextBreakStart, nextBreakEnd, breakIsWhitespace
		if nextMarkupStart and nextMarkupEnd and (not nextSpaceStart or nextMarkupStart < nextSpaceStart) then
			nextBreakStart, nextBreakEnd = nextMarkupStart, nextMarkupEnd
		else
			nextBreakStart, nextBreakEnd = nextSpaceStart or textLength + 1, nextSpaceEnd or textLength + 1
			breakIsWhitespace = true
		end

		local nextWord = nextBreakStart > textPos and string.sub(text, textPos, nextBreakStart - 1) or nil
		local nextBreak = nextBreakStart <= textLength and string.sub(text, nextBreakStart, nextBreakEnd) or nil
		table.insert(labelSeries, nextWord)

		if breakIsWhitespace then
			printSeries(labelSeries)
			if overflown then
				break
			end
			printSeries({nextBreak})
			if overflown then
				textPos = nextBreakStart
				break
			end
			labelSeries = {}
		else
			table.insert(labelSeries, nextBreak)
		end

		textPos = nextBreakEnd + 1
		--textPos = utf8.offset(text, 2, nextBreakEnd)
	end

	if not overflown then
		printSeries(labelSeries)
	end

	----- Alignment layout -----
	local listLayout = Instance.new("UIListLayout")
	listLayout.HorizontalAlignment = properties.ContainerHorizontalAlignment
	listLayout.VerticalAlignment = properties.ContainerVerticalAlignment
	listLayout.Parent = frame

	----- Calculate content size -----
	local contentHeight = 0
	local contentLeft = frame.AbsoluteSize.X
	local contentRight = 0
	for _, lineFrame in pairs(lineFrames) do
		contentHeight = contentHeight + lineFrame.Size.Y.Offset
		local container = lineFrame.Container
		local left, right
		if container.AnchorPoint.X == 0 then
			left = container.Position.X.Offset
			right = container.Size.X.Offset
		elseif container.AnchorPoint.X == 0.5 then
			left = lineFrame.AbsoluteSize.X / 2 - container.Size.X.Offset / 2
			right = lineFrame.AbsoluteSize.X / 2 + container.Size.X.Offset / 2
		elseif container.AnchorPoint.X == 1 then
			left = lineFrame.AbsoluteSize.X - container.Size.X.Offset
			right = lineFrame.AbsoluteSize.X
		end
		contentLeft = math.min(contentLeft, left)
		contentRight = math.max(contentRight, right)
	end

	----- Animation -----
	animationCount = animationCount + 1
	local animationDone = false
	local allTextReached = false
	local overrideYield = false
	local animationRenderstepBinding = "TextAnimation"..animationCount
	local animateQueue = {}

	local function updateAnimations()
		if allTextReached and #animateQueue == 0 or animationDone then
			animationDone = true
			runService:UnbindFromRenderStep(animationRenderstepBinding)
			animateQueue = {}
			return
		end

		local t = tick()
		for i = #animateQueue, 1, -1 do
			local set = animateQueue[i]
			local properties = set.Settings
			local animateStyle = animationStyles[properties.AnimateStyle]
			if not animateStyle then
				warn("No animation style found for: ", properties.AnimateStyle, ", defaulting to Appear")
				animateStyle = animationStyles.Appear
			end
			local animateAlpha = math.min((t - set.Start) / properties.AnimateStyleTime, 1)
			animateStyle(set.Char, animateAlpha, properties)
			if animateAlpha >= 1 then
				table.remove(animateQueue, i)
			end
		end
	end

	local function setFrameToDefault(frame)
		frame.Position = frameProperties[frame].InitialPosition
		frame.Size = frameProperties[frame].InitialSize
		frame.AnchorPoint = frameProperties[frame].InitialAnchorPoint
		for name, value in pairs(frameProperties[frame]) do
			applyProperty(name, value, frame)
		end
	end

	local function setGroupVisible(frame, visible)
		frame.Visible = visible
		for _, v in pairs(frame:GetChildren()) do
			v.Visible = visible
			if visible then
				setFrameToDefault(v)
			end
		end
		if visible and frame:IsA("ImageLabel") then
			setFrameToDefault(frame)
		end
	end

	local function animate(waitForAnimationToFinish)
		animationDone = false
		runService:BindToRenderStep(animationRenderstepBinding, Enum.RenderPriority.Last.Value, updateAnimations)

		local stepGrouping
		local stepTime
		local stepFrequency
		local numAnimated

		-- Make everything invisible to start
		for lineNum, list in pairs(textFrames) do
			for _, frame in pairs(list) do
				setGroupVisible(frame, false)
			end
		end

		local function animateCharacter(char, properties)
			table.insert(animateQueue, {Char = char, Settings = properties, Start = tick()})
		end

		local function yield()
			if not overrideYield and numAnimated % stepFrequency == 0 and stepTime >= 0 then
				local yieldTime = stepTime > 0 and stepTime or nil
				wait(yieldTime)
			end
		end

		for lineNum, list in pairs(textFrames) do
			for _, frame in pairs(list) do
				local properties = frameProperties[frame]
				if not (properties.AnimateStepGrouping  == stepGrouping) or not (properties.AnimateStepFrequency == stepFrequency) then
					numAnimated = 0
				end
				stepGrouping = properties.AnimateStepGrouping
				stepTime = properties.AnimateStepTime
				stepFrequency = properties.AnimateStepFrequency

				if properties.AnimateYield > 0 then
					wait(properties.AnimateYield)
				end

				if stepGrouping == "Word" or stepGrouping == "All" then
					--if not (frame:IsA("TextLabel") and (frame.Text == " ")) then
						if frame:IsA("TextLabel") then
							frame.Visible = true
							for _, v in pairs(frame:GetChildren()) do
								animateCharacter(v, frameProperties[v])
							end
						else
							animateCharacter(frame, properties)
						end
						if stepGrouping == "Word" then
							numAnimated = numAnimated + 1
							yield()
						end
					--end
				elseif stepGrouping == "Letter" then
					if frame:IsA("TextLabel") --[[and not (frame.Text == " ") ]]then
						frame.Visible = true
						local text = frame.Text
						local i = 1
						while true do
							local v = frame:FindFirstChild(string.format("Char%03d", i))
							if not v then
								break
							end
							animateCharacter(v, frameProperties[v])
							numAnimated = numAnimated + 1
							yield()
							if animationDone then
								return
							end
							i = i + 1
						end
					else
						animateCharacter(frame, properties)
						numAnimated = numAnimated + 1
						yield()
					end
				else
					warn("Invalid step grouping: ", stepGrouping)
				end

				if animationDone then
					return
				end
			end
		end

		allTextReached = true

		if waitForAnimationToFinish then
			while #animateQueue > 0 do
				runService.RenderStepped:Wait()
			end
		end
	end

	local textObject = {}

	----- Overflowing -----

	textObject.Overflown = overflown
	textObject.OverflowPickupIndex = textPos
	textObject.StartingProperties = startingProperties
	textObject.OverflowPickupProperties = properties
	textObject.Text = text

	if prevTextObject then
		prevTextObject.NextTextObject = textObject
	end

	-- to overflow: check if textObject.Overflown, then use richText:ContinueOverflow(newFrame, textObject) to continue to another frame.

	----- Return object API -----

	textObject.ContentSize = Vector2.new(contentRight - contentLeft, contentHeight)

	function textObject:Animate(yield)
		if yield then
			animate()
		else
			coroutine.wrap(animate)()
		end
		if self.NextTextObject then
			self.NextTextObject:Animate(yield)
		end
	end

	function textObject:Show(finishAnimation)
		if finishAnimation then
			overrideYield = true
		else
			animationDone = true
			for lineNum, list in pairs(textFrames) do
				for _, frame in pairs(list) do
					setGroupVisible(frame, true)
				end
			end
		end
		if self.NextTextObject then
			self.NextTextObject:Show(finishAnimation)
		end
	end

	function textObject:Hide()
		animationDone = true
		for lineNum, list in pairs(textFrames) do
			for _, frame in pairs(list) do
				setGroupVisible(frame, false)
			end
		end
		if self.NextTextObject then
			self.NextTextObject:Hide()
		end
	end

	return textObject
end

function richText:ContinueOverflow(newFrame, prevTextObject)
	return richText:New(newFrame, nil, nil, false, prevTextObject)
end

return richText