524 lines
14 KiB
Plaintext
524 lines
14 KiB
Plaintext
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!
|