Hello! A few days ago I created a quest system, where you walk up to a NPC and you can click if you’d like to interact. It’s all working as it should. But I’m looking for some help on how I could improve upon it. Right now it’s pretty limited and messy.
Things I’d like to improve:
- The Efficiency of it
- The Readablity
- Ability to add more onto the dialog
Any help would be much appreciated!
Code
local Module = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local MouseButton1Pressed = UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1)
local UIs = ReplicatedStorage:WaitForChild("UIs")
local Player = game.Players.LocalPlayer
local PlayerGui = Player.PlayerGui
local Distance = 12
local Quests = {
Quest_Bridge_Dialog = {
Greeting = "Uh-oh! It looks like this bridge has some missing boards..",
Quest = "Can you find some boards to repair the bridge?",
YesReply = "Great! Come back to me when you've found them!",
NoReply = "Oh well. Maybe later?",
FoundReply = "Good job! Now you can cross the bridge!",
NotFoundReply = "Come back when you've found the boards."
},
Quest_NotBridge_Dialog = {
Greeting = "Uh-oh! I'm Quest_Not_Bridge",
Quest = "Can you find some boards to repair the bridge?",
YesReply = "Great! Come back to me when you've found them!",
NoReply = "Oh well. Maybe later?",
FoundReply = "Good job! Now you can cross the bridge!",
NotFoundReply = "Come back when you've found the boards."
}
}
function Module.CheckQuest(Level)
local IsInteracting = false
local hasFoundItem = false
local Values = {
}
for _, Quest in pairs(game.Workspace[Level]:WaitForChild("Quests"):GetChildren()) do
Values[Quest.Name .. "_IsActive"] = false
end
while wait() do
local IsNearNPC = false
if not IsInteracting then
for _, Quest in pairs(game.Workspace[Level]:WaitForChild("Quests"):GetChildren()) do
local Collider = game.Workspace[Level]:WaitForChild("Quests")[Quest.Name]:WaitForChild("NPC")
if Player:DistanceFromCharacter(Collider.PrimaryPart.Position) <= Distance then
IsNearNPC = true
if PlayerGui:FindFirstChild("QuestDialogUi") == nil then
local DialogUiClone = UIs:WaitForChild("QuestDialogUi"):Clone()
DialogUiClone.Parent = PlayerGui
local Connection
Connection = UserInputService.InputBegan:Connect(function(Input) -- Listens for MouseButton1Click
if Input.UserInputType == Enum.UserInputType.MouseButton1 and IsInteracting == false then
Connection:Disconnect()
Player.Character.Humanoid.WalkSpeed = 0
Player.Character.Humanoid.JumpPower = 0 --Freezes the player
IsInteracting = true
DialogUiClone:WaitForChild("InfoText").Visible = false
DialogUiClone:WaitForChild("Dialog").Visible = true --Shows the Dialog
if Values[Quest.Name .. "_IsActive"] == true then --Checks if Quest is Active, if so, Checks if Found
if hasFoundItem then
for i = 1, string.len(Quests[Quest.Name .. "_Dialog"]["FoundReply"]) do
DialogUiClone.Dialog:WaitForChild("DialogText").Text = DialogUiClone.Dialog:WaitForChild("DialogText").Text..string.sub(Quests[Quest.Name .. "_Dialog"]["FoundReply"],i,i)
wait(.05)
end
else
for i = 1, string.len(Quests[Quest.Name .. "_Dialog"]["NotFoundReply"]) do
DialogUiClone.Dialog:WaitForChild("DialogText").Text = DialogUiClone.Dialog:WaitForChild("DialogText").Text..string.sub(Quests[Quest.Name .. "_Dialog"]["NotFoundReply"],i,i)
wait(.05)
end
end
wait(3)
Player.Character.Humanoid.WalkSpeed = 16
Player.Character.Humanoid.JumpPower = 50 --Unfreezes the player
DialogUiClone:Destroy()
elseif Values[Quest.Name .. "_IsActive"] == false then --Checks if Quest is InActive, if so, loads Greeting
DialogUiClone.Dialog:WaitForChild("DialogText").Text = ""
for i = 1, string.len(Quests[Quest.Name .. "_Dialog"]["Greeting"]) do
DialogUiClone.Dialog:WaitForChild("DialogText").Text = DialogUiClone.Dialog:WaitForChild("DialogText").Text..string.sub(Quests[Quest.Name .. "_Dialog"]["Greeting"],i,i)
wait(.05)
end
DialogUiClone.Dialog:WaitForChild("Next").Visible = true
local NextClick
NextClick = DialogUiClone.Dialog:WaitForChild("Next").MouseButton1Click:Connect(function()
NextClick:Disconnect()
DialogUiClone.Dialog:WaitForChild("Next").Visible = false
DialogUiClone.Dialog:WaitForChild("DialogText").Text = ""
for i = 1, string.len(Quests[Quest.Name .. "_Dialog"]["Quest"]) do
DialogUiClone.Dialog:WaitForChild("DialogText").Text = DialogUiClone.Dialog:WaitForChild("DialogText").Text..string.sub(Quests[Quest.Name .. "_Dialog"]["Quest"],i,i)
wait(.05)
end
DialogUiClone.Dialog:WaitForChild("Choices").Visible = true
local YesClick
YesClick = DialogUiClone.Dialog.Choices:WaitForChild("Yes").MouseButton1Click:Connect(function()
YesClick:Disconnect()
DialogUiClone.Dialog:WaitForChild("Choices").Visible = false
Values[Quest.Name .. "_IsActive"] = true
DialogUiClone.Dialog:WaitForChild("DialogText").Text = ""
for i = 1, string.len(Quests[Quest.Name .. "_Dialog"]["YesReply"]) do
DialogUiClone.Dialog:WaitForChild("DialogText").Text = DialogUiClone.Dialog:WaitForChild("DialogText").Text..string.sub(Quests[Quest.Name .. "_Dialog"]["YesReply"],i,i)
wait(.05)
end
wait(3)
DialogUiClone:Destroy()
Player.Character.Humanoid.WalkSpeed = 16
Player.Character.Humanoid.JumpPower = 50 --Unfreezes the player
IsInteracting = false
end)
local NoClick
NoClick = DialogUiClone.Dialog.Choices:WaitForChild("No").MouseButton1Click:Connect(function()
NoClick:Disconnect()
DialogUiClone.Dialog:WaitForChild("Choices").Visible = false
DialogUiClone.Dialog:WaitForChild("DialogText").Text = ""
for i = 1, string.len(Quests[Quest.Name .. "_Dialog"]["NoReply"]) do
DialogUiClone.Dialog:WaitForChild("DialogText").Text = DialogUiClone.Dialog:WaitForChild("DialogText").Text..string.sub(Quests[Quest.Name .. "_Dialog"]["NoReply"],i,i)
wait(.05)
end
wait(3)
DialogUiClone:Destroy()
Player.Character.Humanoid.WalkSpeed = 16
Player.Character.Humanoid.JumpPower = 50 --Unfreezes the player
IsInteracting = false
end)
end)
end
end
end)
end
elseif Player:DistanceFromCharacter(Collider.PrimaryPart.Position) > Distance and not IsNearNPC then -- Checks if UI is loaded and if the distance is too far, if so, removes UI
if PlayerGui:FindFirstChild("QuestDialogUi") ~= nil then
PlayerGui.QuestDialogUi:Destroy()
end
end
end
end
end
end
return Module
Place File
QuestSystem.rbxl (34.1 KB)
The ModuleScript is in PlayerScripts,
A UI is in ReplicatedStorage,
Everything else is in Workspace