Please read the Notes for information I dont cover much!
Intro
Script
into ServerScriptService
and name it QuestServer
.
Then insert a ModuleScript
into ServerStorage
and name it QuestModule
Scripting
Lets start with our QuestServer
Open up the script and we will create our folders inside the player and require
the QuestModule
local SS = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local questModule = require(SS:FindFirstChild("QuestModule")
Players.PlayerAdded:Connect(function(player)
local questFolder = Instance.new("Folder", player)
questFolder.Name = "Quests"
player.CharacterAdded:Connect(function(character)
task.wait(5)
-- We will come back to this later!
end)
end)
Now, lets create our quest structure in the QuestModule!
local module = {}
local quests = {
["Test"] = {
Requirements = {{"Stick", 1}, {"Metal", 4}};
Rewards = {{"EXP", 125}, {"Gold", 1}};
};
}
return module
Ok, that looks like a lot, but let me explain. First, the ["Test"]
is the name of the quest. So Test
is our quests name.
["Test"]
opens up into another table which will store all of our Requirements and Rewards.
Every Requirement needs its own table like {"Stick", 1}
. This is the same with the rewards.
Add Quest Function To create our
addQuest
function, open the QuestModule!
local module = {}
local quests = {
["Test"] = {
Requirements = {{"Stick", 1}, {"Metal", 4}};
Rewards = {{"EXP", 125}, {"Gold", 1}};
};
}
-- New stuff below
function module.addQuest(plr, questName)
if quests[questName] then -- Makes sure the quest is a valid quest
if checkForQuest(plr, questName) == false then
local quest = quests[questName]
local requirements = quest["Requirements"]
local rewards = quest["Rewards"]
local questFolder = Instance.new("Folder", plr.Data.QuestData)
questFolder.Name = questName
local reqFolder = Instance.new("Folder", questFolder)
reqFolder.Name = "Requirements"
local rewardFolder = Instance.new("Folder", questFolder)
rewardFolder.Name = "Rewards"
for number, requirementStats in pairs(requirements) do
local requirement = requirementStats[1]
local amount = requirementStats[2]
local value = Instance.new("IntValue", reqFolder)
value.Name = requirement
value.Value = amount
end
for number, rewardStats in pairs(rewards) do
local reward = rewardStats[1]
local amount = rewardStats[2]
local value = Instance.new("IntValue", rewardFolder)
value.Name = reward
value.Value = amount
end
end
end
end
return module
Ok, thats alot of code, but let me explain. Most of this explains itself.
First, quests[questName]
checks to make sure the Quest's name is a vaild quest.
Next, the checkForQuest(plr, questName)
is a function that we will get to soon.
Then, we get the Quest and the Requirements and Rewards of the quest.
After that function, we set up the Folders that will store the quest data.
We loop through the requirements and rewards and make a new value for each one. We also name the value to the requirement or reward.
Check For Quest Function Keep the QuestModule open, and lets create a new function called
checkForQuest
!
local module = {}
local quests = {
["Test"] = {
Requirements = {{"Stick", 1}, {"Metal", 4}};
Rewards = {{"EXP", 125}, {"Gold", 1}};
};
}
function module.addQuest(plr, questName)
if quests[questName] then -- Makes sure the quest is a valid quest
if checkForQuest(plr, questName) == false then
local quest = quests[questName]
local requirements = quest["Requirements"]
local rewards = quest["Rewards"]
local questFolder = Instance.new("Folder", plr.Data.QuestData)
questFolder.Name = questName
local reqFolder = Instance.new("Folder", questFolder)
reqFolder.Name = "Requirements"
local rewardFolder = Instance.new("Folder", questFolder)
rewardFolder.Name = "Rewards"
for number, requirementStats in pairs(requirements) do
local requirement = requirementStats[1]
local amount = requirementStats[2]
local value = Instance.new("IntValue", reqFolder)
value.Name = requirement
value.Value = amount
end
for number, rewardStats in pairs(rewards) do
local reward = rewardStats[1]
local amount = rewardStats[2]
local value = Instance.new("IntValue", rewardFolder)
value.Name = reward
value.Value = amount
end
end
end
end
-- New stuff below
function checkForQuest(plr, questName)
if plr.Data.QuestData:FindFirstChild(questName) then
print(plr.Name,"has the quest:",questName)
return true
else
print(plr.Name,"doesn't have the quest:",questName)
return false
end
end
return module
The checkForQuest()
function is very small, but it will allow us to make sure the player doesn't get the same quest.
We get the plr.Data.QuestData
and then try to see if they already have that quest.
Update Quest Function To create our next function, keep the QuestModule open!
local module = {}
local quests = {
["Test"] = {
Requirements = {{"Stick", 1}, {"Metal", 4}};
Rewards = {{"EXP", 125}, {"Gold", 1}};
};
}
function module.addQuest(plr, questName)
if quests[questName] then -- Makes sure the quest is a valid quest
if checkForQuest(plr, questName) == false then
local quest = quests[questName]
local requirements = quest["Requirements"]
local rewards = quest["Rewards"]
local questFolder = Instance.new("Folder", plr.Data.QuestData)
questFolder.Name = questName
local reqFolder = Instance.new("Folder", questFolder)
reqFolder.Name = "Requirements"
local rewardFolder = Instance.new("Folder", questFolder)
rewardFolder.Name = "Rewards"
for number, requirementStats in pairs(requirements) do
local requirement = requirementStats[1]
local amount = requirementStats[2]
local value = Instance.new("IntValue", reqFolder)
value.Name = requirement
value.Value = amount
end
for number, rewardStats in pairs(rewards) do
local reward = rewardStats[1]
local amount = rewardStats[2]
local value = Instance.new("IntValue", rewardFolder)
value.Name = reward
value.Value = amount
end
end
end
end
function checkForQuest(plr, questName)
if plr.Data.QuestData:FindFirstChild(questName) then
print(plr.Name,"has the quest:",questName)
return true
else
print(plr.Name,"doesn't have the quest:",questName)
return false
end
end
-- New stuff below
function module.updateQuest(plr, questName, action)
if quests[questName] then
for i, quest in pairs(plr.Data.QuestData:GetChildren()) do
if quest.Requirements:FindFirstChild(action) then
if quest.Requirements:FindFirstChild(action).Value > 0 then
quest.Requirements:FindFirstChild(action).Value -= 1
end
end
end
completeQuest(plr, questName)
end
end
return module
Ok, so this is how we are gonna update the player's quests when they do a action in your game.
If we find that one of the requirements are named the exactly the same as the action, then we will update the requirement.
At the very end, we have the completeQuest
function. We will cover that next!
Complete Quest Function Last function in the QuestModule!
local module = {}
local quests = {
["Test"] = {
Requirements = {{"Stick", 1}, {"Metal", 4}};
Rewards = {{"EXP", 125}, {"Gold", 1}};
};
}
function module.addQuest(plr, questName)
if quests[questName] then -- Makes sure the quest is a valid quest
if checkForQuest(plr, questName) == false then
local quest = quests[questName]
local requirements = quest["Requirements"]
local rewards = quest["Rewards"]
local questFolder = Instance.new("Folder", plr.Data.QuestData)
questFolder.Name = questName
local reqFolder = Instance.new("Folder", questFolder)
reqFolder.Name = "Requirements"
local rewardFolder = Instance.new("Folder", questFolder)
rewardFolder.Name = "Rewards"
for number, requirementStats in pairs(requirements) do
local requirement = requirementStats[1]
local amount = requirementStats[2]
local value = Instance.new("IntValue", reqFolder)
value.Name = requirement
value.Value = amount
end
for number, rewardStats in pairs(rewards) do
local reward = rewardStats[1]
local amount = rewardStats[2]
local value = Instance.new("IntValue", rewardFolder)
value.Name = reward
value.Value = amount
end
end
end
end
function checkForQuest(plr, questName)
if plr.Data.QuestData:FindFirstChild(questName) then
print(plr.Name,"has the quest:",questName)
return true
else
print(plr.Name,"doesn't have the quest:",questName)
return false
end
end
function module.updateQuest(plr, questName, action)
if quests[questName] then
for i, quest in pairs(plr.Data.QuestData:GetChildren()) do
if quest.Requirements:FindFirstChild(action) then
if quest.Requirements:FindFirstChild(action).Value > 0 then
quest.Requirements:FindFirstChild(action).Value -= 1
end
end
end
completeQuest(plr, questName)
end
end
-- New stuff below
function completeQuest(plr, questName)
if checkForQuest(plr, questName) == true then
local questData = plr.Data.QuestData:FindFirstChild(questName)
local requirements = questData:FindFirstChild("Requirements")
local rewards = questData:FindFirstChild("Rewards")
for i, v in pairs(requirements:GetChildren()) do
if v.Value ~= 0 then
print(plr.Name,"hasn't completed all the requirements!")
return
else
for number, reward in pairs(rewards:GetChildren()) do
if reward.Name == "EXP" then
-- Give the player EXP (Or whatever your reward was!)
end
end
questData:Destroy()
end
end
end
end
return module
We are almost done! Now let me explain what the completeQuest
function does.
Once again, we use the checkForQuest
function. If the player has the quest, then we can give them there rewards.
We do one last check to make sure all the requirement's values are at 0, meaning that we have completed them all.
If the player did complete all of there requirements, then we loop though all of the rewards for the quest. We check the name of the reward and give the player the reward that they earned!
Giving the player a quest Note: For now, we will be Hard Coding the quest in. If you do want to make a NPC give a quest, make sure to use the addQuest function from the server ONLY. You will also want to always keep updating the players quest using the updateQuest function. I will talk about this a bit later!
Remember the QuestServer
script? Well you will need to enter that script now!
Lets Hard Code the quest in for now. Please read the note just above this message if you want to know how to add it into a NPC.
local SS = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local questModule = require(SS:FindFirstChild("QuestModule")
Players.PlayerAdded:Connect(function(player)
local questFolder = Instance.new("Folder", player)
questFolder.Name = "Quests"
player.CharacterAdded:Connect(function(character)
task.wait(5)
-- New stuff below
spawn(function()
questModule.addQuest(player, "Test")
end)
end)
end)
Ok, so we have called the addQuest
function after 5 seconds.
Remember, that the addQuest
function will now give the player there new quest "Test".
NOTES
So, I said I would talk more about adding the quest to a NPC. Adding this quest system into a NPC is easy! You will need to know how to use Remote Events. You will need UI with a button to accept the quest. Once the player clicks the button, then you will want to Fire the Remote Event. Now, please take note that when you fire a Remote Event on the client, hackers can easily accepts every quest without talking to the NPC. Once you use Fire the Remote Event, use the .OnServerEvent
and from there, use the addQuest
function. Make sure you pass the right varibles into the function! addQuest(player, questName)
EXAMPLE:
Client
button.MouseButton1Up:Connect(function()
remoteEvent:FireServer(questName)
end)
Server
remoteEvent.OnServerEvent:Connect(function(plr, questName)
questModule.addQuest(plr, questName)
end)
How to Update the quests
If you have a item pickup system, or a part that the player will need to touch to update the quest, this will work. You will need a Item Pickup system or a Part Touching System.
I am only going to show how to update the quest if the player touches a part.
EXAMPLE:
Server
part.Touched:Connect(function(hit)
if game:GetService("Players"):FindFirstChild(hit.Parent.Name) then
questModule.updateQuest(game:GetService("Players"):FindFirstChild(hit.Parent.Name, part.QuestName.Value, "Reached Bandits Village")
end
end)
I know I didn't use a debounce, but you could add one if you wanted. The part that you have to touch to reach the end must have a StringValue
inside of the part. This StringValue
must be named "QuestName". The value of the StringValue
will be the quest that you will update once you touch the part. The updateQuest()
needs 3 parameters, updateQuest(plr, questName, action)
.
Ending
I hope this helped! Keep in mind that I didn't use the best methods, but they work! Also, I'm sorry that I didn't use any pictures. Anyways, I put a lot of time into this and I would like if you guys have any feedback to post it into the comments below!
Thanks for much for reading this!!
Thanks - Witch(@witch2352)