import "macros" as { $ } $load $FILE -- Heliodex's basic New function (basically a simplified version of melt) New = (className, name, props) -> if not props? -- no name was provided props = name name = nil obj = Instance.new className obj.Name = name if name local parent for k, v in pairs props if type(k) == "string" then if k == "Parent" parent = v else obj[k] = v elseif type(k) == "number" and type(v) == "userdata" v.Parent = obj obj.Parent = parent obj -- waitForProperty = (instance, name) -> until instance[name] instance.Changed\wait! waitForChild = (instance, name) -> until instance\FindFirstChild name instance.ChildAdded\wait! local mainFrame choices = {} local lastChoice choiceMap = {} local currentConversationDialog local currentConversationPartner local currentAbortDialogScript tooFarAwayMessage = "You are too far away to chat!" tooFarAwaySize = 300 characterWanderedOffMessage = "Chat ended because you walked away" characterWanderedOffSize = 350 conversationTimedOut = "Chat ended because you didn't reply" conversationTimedOutSize = 350 local player local chatNotificationGui local messageDialog local timeoutScript local reenableDialogScript dialogMap = {} dialogConnections = {} local gui waitForChild game, "CoreGui" waitForChild game.CoreGui, "RobloxGui" if game.CoreGui.RobloxGui\FindFirstChild "ControlFrame" gui = game.CoreGui.RobloxGui.ControlFrame else gui = game.CoreGui.RobloxGui currentTone = -> if currentConversationDialog currentConversationDialog.Tone else Enum.DialogTone.Neutral createChatNotificationGui = -> chatNotificationGui = New "BillboardGui", "ChatNotificationGui" ExtentsOffset: Vector3.new 0, 1, 0 Size: UDim2.new 4, 0, 5.42857122, 0 SizeOffset: Vector2.new 0, 0 StudsOffset: Vector3.new 0.4, 4.3, 0 Enabled: true RobloxLocked: true Active: true * New "ImageLabel", "Image" Active: false BackgroundTransparency: 1 Position: UDim2.new 0, 0, 0, 0 Size: UDim2.new 1, 0, 1, 0 Image: "" RobloxLocked: true * New "ImageButton", "Button" AutoButtonColor: false Position: UDim2.new 0.088, 0, 0.053, 0 Size: UDim2.new 0.83, 0, 0.46, 0 Image: "" BackgroundTransparency: 1 RobloxLocked: true getChatColor = (tone) -> if tone == Enum.DialogTone.Neutral Enum.ChatColor.Blue elseif tone == Enum.DialogTone.Friendly Enum.ChatColor.Green elseif tone == Enum.DialogTone.Enemy Enum.ChatColor.Red resetColor = (frame, tone) -> if tone == Enum.DialogTone.Neutral frame.BackgroundColor3 = Color3.new 0, 0, 179 / 255 frame.Number.TextColor3 = Color3.new 45 / 255, 142 / 255, 245 / 255 elseif tone == Enum.DialogTone.Friendly frame.BackgroundColor3 = Color3.new 0, 77 / 255, 0 frame.Number.TextColor3 = Color3.new 0, 190 / 255, 0 elseif tone == Enum.DialogTone.Enemy frame.BackgroundColor3 = Color3.new 140 / 255, 0, 0 frame.Number.TextColor3 = Color3.new 255 / 255, 88 / 255, 79 / 255 styleChoices = (tone) -> for _, obj in pairs choices resetColor obj, tone resetColor lastChoice, tone styleMainFrame = (tone) -> if tone == Enum.DialogTone.Neutral mainFrame.Style = Enum.FrameStyle.ChatBlue mainFrame.Tail.Image = "rbxasset://textures/chatBubble_botBlue_tailRight.png" elseif tone == Enum.DialogTone.Friendly mainFrame.Style = Enum.FrameStyle.ChatGreen mainFrame.Tail.Image = "rbxasset://textures/chatBubble_botGreen_tailRight.png" elseif tone == Enum.DialogTone.Enemy mainFrame.Style = Enum.FrameStyle.ChatRed mainFrame.Tail.Image = "rbxasset://textures/chatBubble_botRed_tailRight.png" styleChoices tone setChatNotificationTone = (gui, purpose, tone) -> gui.Image.Image = if tone == Enum.DialogTone.Neutral "rbxasset://textures/chatBubble_botBlue_notify_bkg.png" elseif tone == Enum.DialogTone.Friendly "rbxasset://textures/chatBubble_botGreen_notify_bkg.png" elseif tone == Enum.DialogTone.Enemy "rbxasset://textures/chatBubble_botRed_notify_bkg.png" gui.Image.Button.Image = if purpose == Enum.DialogPurpose.Quest "rbxasset://textures/chatBubble_bot_notify_bang.png" elseif purpose == Enum.DialogPurpose.Help "rbxasset://textures/chatBubble_bot_notify_question.png" elseif purpose == Enum.DialogPurpose.Shop "rbxasset://textures/chatBubble_bot_notify_money.png" createMessageDialog = -> messageDialog = New "Frame", "DialogScriptMessage" Style: Enum.FrameStyle.RobloxRound Visible: false * New "TextLabel", "Text" Position: UDim2.new 0, 0, 0, -1 Size: UDim2.new 1, 0, 1, 0 FontSize: Enum.FontSize.Size14 BackgroundTransparency: 1 TextColor3: Color3.new 1, 1, 1 RobloxLocked: true showMessage = (msg, size) -> with messageDialog .Text.Text = msg .Size = UDim2.new 0, size, 0, 40 .Position = UDim2.new 0.5, -size / 2, 0.5, -40 .Visible = true wait 2 .Visible = false variableDelay = (str) -> length = math.min string.len(str), 100 wait 0.75 + (length / 75) * 1.5 highlightColor = (frame, tone) -> if tone == Enum.DialogTone.Neutral frame.BackgroundColor3 = Color3.new 2 / 255, 108 / 255, 255 / 255 frame.Number.TextColor3 = Color3.new 1, 1, 1 elseif tone == Enum.DialogTone.Friendly frame.BackgroundColor3 = Color3.new 0, 128 / 255, 0 frame.Number.TextColor3 = Color3.new 1, 1, 1 elseif tone == Enum.DialogTone.Enemy frame.BackgroundColor3 = Color3.new 204 / 255, 0, 0 frame.Number.TextColor3 = Color3.new 1, 1, 1 endDialog = -> if currentAbortDialogScript currentAbortDialogScript\Remove! currentAbortDialogScript = nil dialog = currentConversationDialog currentConversationDialog = nil if dialog and dialog.InUse reenableScript = reenableDialogScript\Clone! reenableScript.archivable = false reenableScript.Disabled = false reenableScript.Parent = dialog for dialog, gui in pairs dialogMap if dialog and gui gui.Enabled = not dialog.InUse currentConversationPartner = nil wanderDialog = -> print "Wander" mainFrame.Visible = false endDialog! showMessage characterWanderedOffMessage, characterWanderedOffSize timeoutDialog = -> print "Timeout" mainFrame.Visible = false endDialog! showMessage conversationTimedOut, conversationTimedOutSize normalEndDialog = -> print "Done" endDialog! sanitizeMessage = (msg) -> if string.len(msg) == 0 "..." else msg renewKillswitch = (dialog) -> with currentAbortDialogScript if currentAbortDialogScript \Remove! currentAbortDialogScript = nil currentAbortDialogScript = timeoutScript\Clone! .archivable = false .Disabled = false .Parent = dialog presentDialogChoices = (talkingPart, dialogChoices) -> return if not currentConversationDialog currentConversationPartner = talkingPart sortedDialogChoices = {} for _, obj in pairs dialogChoices if obj\IsA "DialogChoice" table.insert sortedDialogChoices, obj table.sort sortedDialogChoices, (a, b) -> a.Name < b.Name if #sortedDialogChoices == 0 normalEndDialog! return pos = 1 yPosition = 0 choiceMap = {} for _, obj in pairs choices obj.Visible = false for _, obj in pairs sortedDialogChoices if pos <= #choices --3 lines is the maximum, set it to that temporarily choices[pos].Size = UDim2.new 1, 0, 0, 24 * 3 choices[pos].UserPrompt.Text = obj.UserDialog height = math.ceil(choices[pos].UserPrompt.TextBounds.Y / 24) * 24 choices[pos].Position = UDim2.new 0, 0, 0, yPosition choices[pos].Size = UDim2.new 1, 0, 0, height choices[pos].Visible = true choiceMap[choices[pos]] = obj yPosition += height pos += 1 lastChoice.Position = UDim2.new 0, 0, 0, yPosition lastChoice.Number.Text = pos .. ")" mainFrame.Size = UDim2.new 0, 350, 0, yPosition + 24 + 32 mainFrame.Position = UDim2.new 0, 20, 0, -mainFrame.Size.Y.Offset - 20 styleMainFrame currentTone! mainFrame.Visible = true selectChoice = (choice) -> renewKillswitch currentConversationDialog --First hide the Gui mainFrame.Visible = false if choice == lastChoice game.Chat\Chat game.Players.LocalPlayer.Character, "Goodbye!", getChatColor(currentTone!) normalEndDialog! else dialogChoice = choiceMap[choice] game.Chat\Chat( game.Players.LocalPlayer.Character, sanitizeMessage(dialogChoice.UserDialog), getChatColor currentTone! ) wait 1 currentConversationDialog\SignalDialogChoiceSelected player, dialogChoice game.Chat\Chat( currentConversationPartner, sanitizeMessage(dialogChoice.ResponseDialog), getChatColor currentTone! ) variableDelay dialogChoice.ResponseDialog presentDialogChoices currentConversationPartner, dialogChoice\GetChildren! newChoice = (numberText) -> frame = New "TextButton" BackgroundColor3: Color3.new 0, 0, 179 / 255 AutoButtonColor: false BorderSizePixel: 0 Text: "" RobloxLocked: true * New "TextLabel", "Number" TextColor3: Color3.new 127 / 255, 212 / 255, 255 / 255 Text: numberText FontSize: Enum.FontSize.Size14 BackgroundTransparency: 1 Position: UDim2.new 0, 4, 0, 2 Size: UDim2.new 0, 20, 0, 24 TextXAlignment: Enum.TextXAlignment.Left TextYAlignment: Enum.TextYAlignment.Top RobloxLocked: true * New "TextLabel", "UserPrompt" BackgroundTransparency: 1 TextColor3: Color3.new 1, 1, 1 FontSize: Enum.FontSize.Size14 Position: UDim2.new 0, 28, 0, 2 Size: UDim2.new 1, -32, 1, -4 TextXAlignment: Enum.TextXAlignment.Left TextYAlignment: Enum.TextYAlignment.Top TextWrap: true RobloxLocked: true frame.MouseEnter\connect -> highlightColor frame, currentTone! frame.MouseLeave\connect -> resetColor frame, currentTone! frame.MouseButton1Click\connect -> selectChoice frame frame initialize = (parent) -> choices[1] = newChoice "1)" choices[2] = newChoice "2)" choices[3] = newChoice "3)" choices[4] = newChoice "4)" lastChoice = newChoice "5)" lastChoice.UserPrompt.Text = "Goodbye!" lastChoice.Size = UDim2.new 1, 0, 0, 28 mainFrame = New "Frame", "UserDialogArea" Size: UDim2.new 0, 350, 0, 200 Style: Enum.FrameStyle.ChatBlue Visible: false * New "ImageLabel", "Tail" Size: UDim2.new 0, 62, 0, 53 Position: UDim2.new 1, 8, 0.25 Image: "rbxasset://textures/chatBubble_botBlue_tailRight.png" BackgroundTransparency: 1 RobloxLocked: true for _, obj in pairs choices obj.RobloxLocked = true obj.Parent = mainFrame lastChoice.RobloxLocked = true lastChoice.Parent = mainFrame mainFrame.RobloxLocked = true mainFrame.Parent = parent doDialog = (dialog) -> until Instance.Lock dialog, player wait! if dialog.InUse Instance.Unlock dialog return else dialog.InUse = true Instance.Unlock dialog currentConversationDialog = dialog game.Chat\Chat dialog.Parent, dialog.InitialPrompt, getChatColor dialog.Tone variableDelay dialog.InitialPrompt presentDialogChoices dialog.Parent, dialog\GetChildren! checkForLeaveArea = -> while currentConversationDialog if currentConversationDialog.Parent and ( player\DistanceFromCharacter currentConversationDialog.Parent.Position >= currentConversationDialog.ConversationDistance ) wanderDialog! wait 1 startDialog = (dialog) -> if dialog.Parent and dialog.Parent\IsA "BasePart" if player\DistanceFromCharacter(dialog.Parent.Position) >= dialog.ConversationDistance showMessage tooFarAwayMessage, tooFarAwaySize return for dialog, gui in pairs dialogMap if dialog and gui gui.Enabled = false renewKillswitch dialog delay 1, checkForLeaveArea doDialog dialog removeDialog = (dialog) -> if dialogMap[dialog] dialogMap[dialog]\Remove! dialogMap[dialog] = nil if dialogConnections[dialog] dialogConnections[dialog]\disconnect! dialogConnections[dialog] = nil addDialog = (dialog) -> if dialog.Parent if dialog.Parent\IsA "BasePart" chatGui = chatNotificationGui\clone! with chatGui .Enabled = not dialog.InUse .Adornee = dialog.Parent .RobloxLocked = true .Parent = game.CoreGui .Image.Button.MouseButton1Click\connect -> startDialog dialog setChatNotificationTone chatGui, dialog.Purpose, dialog.Tone dialogMap[dialog] = chatGui dialogConnections[dialog] = dialog.Changed\connect (prop) -> if prop == "Parent" and dialog.Parent --This handles the reparenting case, seperate from removal case removeDialog dialog addDialog dialog elseif prop == "InUse" chatGui.Enabled = not currentConversationDialog and not dialog.InUse if dialog == currentConversationDialog timeoutDialog! elseif prop == "Tone" or prop == "Purpose" setChatNotificationTone chatGui, dialog.Purpose, dialog.Tone else -- still need to listen to parent changes even if current parent is not a BasePart dialogConnections[dialog] = dialog.Changed\connect (prop) -> if prop == "Parent" and dialog.Parent --This handles the reparenting case, seperate from removal case removeDialog dialog addDialog dialog fetchScripts = -> model = game\GetService"InsertService"\LoadAsset 39226062 if type(model) == "string" -- load failed, lets try again wait 0.1 model = game\GetService"InsertService"\LoadAsset 39226062 return if type(model) == "string" -- not going to work, lets bail waitForChild model, "TimeoutScript" timeoutScript = model.TimeoutScript waitForChild model, "ReenableDialogScript" reenableDialogScript = model.ReenableDialogScript onLoad = -> waitForProperty game.Players, "LocalPlayer" player = game.Players.LocalPlayer waitForProperty player, "Character" --print "Fetching Scripts" fetchScripts! --print "Creating Guis" createChatNotificationGui! --print "Creating MessageDialog" createMessageDialog! messageDialog.RobloxLocked = true messageDialog.Parent = gui --print "Waiting for BottomLeftControl" waitForChild gui, "BottomLeftControl" --print "Initializing Frame" frame = New "Frame", "DialogFrame" Position: UDim2.new 0, 0, 0, 0 Size: UDim2.new 0, 0, 0, 0 BackgroundTransparency: 1 RobloxLocked: true Parent: gui.BottomLeftControl initialize frame --print "Adding Dialogs" game.CollectionService.ItemAdded\connect (obj) -> if obj\IsA "Dialog" addDialog obj game.CollectionService.ItemRemoved\connect (obj) -> if obj\IsA "Dialog" removeDialog obj for _, obj in pairs game.CollectionService\GetCollection "Dialog" if obj\IsA "Dialog" addDialog obj onLoad!