I’m trying to make it so that as soon as the player meets the requirement for the quest like as soon as they hit the stats required or class required ect. They should have my beam appear for them. Also it should appear if you first joined the game
The issue is I don’t know how to do this like make something appear if as soon as you meet those requirements and appear if your first playing the game.
This is my arrow local script in scs
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
-- Wait for the character to load
local character = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
local targetPart = workspace:WaitForChild("QuestAreaArrow") -- Reference to the QuestAreaArrow part
print("QuestAreaArrow found:", targetPart)
-- Create the first Beam (Guiding Beam)
local beam1 = Instance.new("Beam")
beam1.TextureLength = 0 -- No texture on this beam
beam1.TextureSpeed = 0 -- No movement for guiding beam
beam1.Width0 = 1.5
beam1.Width1 = 1.5
beam1.Transparency = NumberSequence.new(1) -- Fully transparent background
-- Create Attachments for the first Beam
local attachment0 = Instance.new("Attachment", humanoidRootPart)
attachment0.Name = "GuideAttachment"
attachment0.Position = Vector3.new(0, 0, 0) -- Position slightly above the player
print("Attachment0 created:", attachment0)
local attachment1 = Instance.new("Attachment", targetPart) -- Attach to QuestAreaArrow part
attachment1.Name = "TargetAttachment"
attachment1.Position = Vector3.new(0, 0, 0) -- This will set the attachment's position relative to the part
print("Attachment1 created:", attachment1)
-- Set the first beam's attachments
beam1.Attachment0 = attachment0
beam1.Attachment1 = attachment1
-- Parent the first beam to the workspace
beam1.Parent = workspace
print("Beam1 created and parented to workspace.")
-- Create the second Beam (Arrow Beam)
local beam2 = Instance.new("Beam")
beam2.Texture = "rbxassetid://76564571897615" -- Example texture (arrow image)
beam2.TextureSpeed = 5 -- Adjust the speed of the texture moving along the beam
beam2.Width0 = 2.5
beam2.Width1 = 2.5
-- Set the second beam's attachments
beam2.Attachment0 = attachment0
beam2.Attachment1 = attachment1
-- Parent the second beam to the workspace
beam2.Parent = workspace
print("Beam2 created and parented to workspace.")
-- Update the TextureLength based on distance using RunService
RunService.RenderStepped:Connect(function()
local distance = (humanoidRootPart.Position - targetPart.Position).Magnitude
local textureLength
if distance < 50 then -- 10 * 10
textureLength = 12
elseif distance < 1000 then -- 100 * 10
textureLength = math.clamp(10 + (distance - 50) * (490 / 900), 10, 300) -- Adjusted to reflect new thresholds
else
textureLength = 300
end
-- Smooth transition: Adjust TextureLength gradually
beam2.TextureLength = beam2.TextureLength * 0.8 + textureLength * 0.2
end)
-- Clean up when the player character dies
character:WaitForChild("Humanoid").Died:Connect(function()
beam1:Destroy()
beam2:Destroy()
attachment0:Destroy()
attachment1:Destroy()
print("Cleaned up beams and attachments for player:", player.Name)
end)
And this is my quest module
local RS = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
--// Variables
local RSmodules = RS.Modules
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local BigNum = require(RSmodules.BigNum)
local CREvents = RS.Remotes.Client.Events
local TypeQuestDialog = CREvents.TypeQuestDialog
--// Module
local Quests = {}
Quests.__index = Quests
Quests.Givers = {
"Giver1"
}
Quests.QuestTable = {
{ -- Giver1's Quests
{
["Name"] = "The Rise of a Warrior...",
["Dialog"] = {
"Welcome! Glad you were able to make it, we've been expecting you young warrior.",
"You will be trained to become one of the strongest warriors known to mankind!",
"Now, for your first task: gain 30 strength and 30 endurance. Seems easy enough, right?"
},
["NotfinishedText"] = "Come back to me once you've reached 30 Strength and 30 Endurance.",
["Stats"] = {
["Strength"] = 30,
["Endurance"] = 30
},
["Status"] = "Innocent",
["Class"] = "F-Class", -- Required class for this quest
["Fusion"] = "None",
["Rewards"] = {
["Tokens"] = 250,
["FireballAbility"] = true,
["LightningAbility"] = true,
["SoulharvestAbility"] = true,
["ElasticalAbility"] = true,
["EnergyPunchAbility"] = true,
["WalkOnWaterAbility"] = true,
["DamageReflectionAbility"] = true,
["TeleportationAbility"] = true,
["FlyAbility"] = true,
["InvisibilityAbility"] = true
}
},
{
["Name"] = "Intelligence is the key...",
["Dialog"] = {
"HAHA! I knew you wouldn't be able to... wait... you did it?.",
"I'm honestly impressed, didn't know you were worthy enough for what's about to come!",
"Now, for your second task: gain 30 psychic. Let's see if you're smart enough for this."
},
["NotfinishedText"] = "Come back to me once you've reached 30 Psychic.",
["Stats"] = {
["Psychic"] = 30
},
["Rewards"] = {
["Tokens"] = 400
}
},
{
["Name"] = "The warrior of speed",
["Dialog"] = {
"Impressive work! You are indeed smart enough to continue to the rest of the challenges.",
"But are you fast enough to escape deadly enemies that will come your way? Or maybe you are the enemy.",
"Now, for your third task: gain 50 speed. Maybe we shall race after."
},
["NotfinishedText"] = "Come back to me once you've reached 50 Speed.",
["Stats"] = {
["Speed"] = 50
},
["Rewards"] = {
["Tokens"] = 750
}
},
{
["Name"] = "Mind over matter",
["Dialog"] = {
"From the looks of it you'll be running faster than flash soon!",
"But let's take a chill pill and think about how we will become the most secret warriors known to mankind",
"Now, for your fourth task: gain 200 Psychic. Think about your up and coming greatness"
},
["NotfinishedText"] = "Come back to me once you've reached 200 Psychic. There's a special skill waiting for you :)",
["Stats"] = {
["Psychic"] = 200
},
["Rewards"] = {
["Tokens"] = 1000
}
}
}
}
-- Function to abbreviate numbers
local function abbreviateNumber(value)
local num = tonumber(value)
if not num then return value end -- Return original if not a number
local suffixes = { "", "K", "M", "B", "T", "Qa", "Qi", "Sx", "Sp", "Oc", "N", "Dc", "Ud", "Td", "Dd", "Qua", "Qui", "Sxd", "Spd", "Ocd", "Nod", "Vg" }
local index = 1
while num >= 1000 and index < #suffixes do
num = num / 1000
index = index + 1
end
local formattedNumber = string.format("%.2f", num)
-- Remove trailing zeros
formattedNumber = formattedNumber:gsub("%.?0*$", "")
return formattedNumber .. suffixes[index]
end
local function FindNextQuest(player, giverNum)
local curQuestInfo = string.split(player.QuestId.Value, "|") -- [questGiver, questNum]
local curQuestGiver = tonumber(curQuestInfo[1])
local curQuestId = tonumber(curQuestInfo[2])
-- Check for valid quest giver
if not Quests.QuestTable[curQuestGiver] then
return {nil, "InvalidGiver"}
end
if curQuestId == 0 and curQuestGiver == 1 then
player.QuestId.Value = "1|1"
return {Quests.QuestTable[1][1], "New Quest"}
elseif curQuestId == 0 and curQuestGiver > 1 then
local state = (#Quests.Givers >= curQuestGiver) and "DoneWithThisGiver" or "NoMoreQuests"
if state == "NoMoreQuests" then return {nil, state} end
if curQuestGiver == giverNum then
player.QuestId.Value = curQuestGiver.."|1"
return {Quests.QuestTable[curQuestGiver][1], "New Quest"}
end
end
local currentQuest = Quests.QuestTable[curQuestGiver][curQuestId]
-- Check if the quest is valid
if not currentQuest then
return {nil, "InvalidQuest"}
end
if Quests.CurrentQuestCompleted(player) == false then
return {currentQuest, "Hasn't Finished"}
end
-- Check class requirement
local playerClass = player.leaderstats.Class.Value
if currentQuest.Class and playerClass ~= currentQuest.Class then
return {currentQuest, "ClassRequirementNotMet"}
end
local playerFusion = player.leaderstats.Fusion.Value
if currentQuest.Fusion and playerFusion ~= currentQuest.Fusion then
return {currentQuest, "ClassRequirementNotMet"}
end
local playerStatus = player.leaderstats.Status.Value
if currentQuest.Status and playerStatus ~= currentQuest.Status then
return {currentQuest, "ClassRequirementNotMet"}
end
local Currency = player.Currency
Currency.Tokens.Value += currentQuest["Rewards"].Tokens
-- Set Abilities if specified in the rewards
local abilities = player:FindFirstChild("Abilities")
if abilities then
local abilityMapping = {
FireballAbility = "Fireball",
LightningAbility = "LightningStrike",
SoulharvestAbility = "SoulHarvest",
ElasticalAbility = "Elastical",
EnergyPunchAbility = "EnergyPunch",
WalkOnWaterAbility = "WalkOnWater",
DamageReflectionAbility = "DamageReflection",
TeleportationAbility = "Teleport",
FlyAbility = "Fly",
InvisibilityAbility = "Invisibility"
}
for reward, abilityName in pairs(abilityMapping) do
if currentQuest["Rewards"][reward] then
local ability = abilities:FindFirstChild(abilityName)
if ability then
ability.Value = true
-- Initialize the equipped state
local equipped = abilities:FindFirstChild(abilityName.."Equipped")
if equipped then
equipped.Value = true -- Start as not equipped
end
end
end
end
end
-- TODO: Enable powers if needed
if currentQuest["Rewards"]["Power"] then
-- Implement power enabling logic
end
-- Find New Quest
local state = "New Quest"
if (curQuestId + 1 <= #Quests.QuestTable[curQuestGiver]) then
curQuestId += 1
player.QuestId.Value = curQuestGiver.."|"..curQuestId
return {Quests.QuestTable[curQuestGiver][curQuestId], state}
else
player.QuestId.Value = (curQuestGiver + 1).."|0"
curQuestGiver += 1
curQuestId = 0
state = (#Quests.Givers >= curQuestGiver and "DoneWithThisGiver" or "NoMoreQuests")
return {nil, state}
end
end
function Quests.CurrentQuestCompleted(player)
local curQuestInfo = string.split(player.QuestId.Value, "|") -- [questGiver, questNum]
local curQuestGiverNum = tonumber(curQuestInfo[1])
local curQuestId = tonumber(curQuestInfo[2])
local curQuestGiver = Quests.QuestTable[curQuestGiverNum]
if not curQuestGiver then return true end
local curQuest = curQuestGiver[curQuestId]
if curQuest == nil then return true end
local pStats = player.PhysicalStats
for Stat, Req in pairs(curQuest.Stats) do
if not BigNum.mt.ge(pStats[Stat].Value, Req) then
return false
end
end
-- Check class requirement
local playerClass = player.leaderstats.Class.Value
if curQuest.Class and playerClass ~= curQuest.Class then
return false
end
local playerFusion = player.leaderstats.Fusion.Value
if curQuest.Fusion and playerFusion ~= curQuest.Fusion then
return false
end
local playerStatus = player.leaderstats.Status.Value
if curQuest.Status and playerStatus ~= curQuest.Status then
return false
end
return true
end
function Quests.GiveQuest(Player, giverNum)
local newQuest = {}
-- Find the next quest and its state specific to the player
local NextQuestData = FindNextQuest(Player, giverNum)
local NextQuest = NextQuestData[1]
local State = NextQuestData[2]
-- Initialize the new quest based on state
if State == "New Quest" then
newQuest = NextQuest or {}
newQuest.CurrentDialog = 0
newQuest.State = State
else
newQuest = NextQuest or {}
newQuest.State = State
-- Make sure NotFinishedText is player-specific or dynamic if needed
newQuest.NotFinishedText = NextQuest and NextQuest.NotfinishedText or "You have not completed the required tasks yet."
end
-- Ensure PlayerData is initialized correctly
newQuest.PlayerData = newQuest.PlayerData or {}
function newQuest:PerformDialog(Player)
-- Initialize playerData for the specific player if it doesn't exist
local playerData = self.PlayerData[Player.UserId]
if not playerData then
playerData = { CurrentDialog = 0 }
self.PlayerData[Player.UserId] = playerData
end
-- Check the current state and perform the appropriate action
if self.State == "Hasn't Finished" then
-- Make sure NotFinishedText is specific to the current quest
local notFinishedText = self.NotFinishedText or "You have not completed the required tasks yet."
TypeQuestDialog:FireClient(Player, notFinishedText, true)
return
elseif self.State == "DoneWithThisGiver" then
TypeQuestDialog:FireClient(Player, "Find the next quest giver!", true)
return
elseif self.State == "NoMoreQuests" then
TypeQuestDialog:FireClient(Player, "Congratulations! You have completed all the quests. More quests coming soon, keep on grinding.", true)
return
end
-- Increment dialog index only for the specific player
playerData.CurrentDialog = playerData.CurrentDialog + 1
local dialog = self.Dialog[playerData.CurrentDialog]
-- Determine if it's the last dialog for this player
local isLastDialog = self.Dialog[playerData.CurrentDialog + 1] == nil
if isLastDialog then
-- Only add to the quest list if it is not the first dialog
if playerData.CurrentDialog > 1 then
self:AddToQuestList(Player)
end
else
-- Add to quest list if it's the first dialog
if playerData.CurrentDialog == 1 then
self:AddToQuestList(Player)
end
end
-- Send the dialog to the specific player
TypeQuestDialog:FireClient(Player, dialog, isLastDialog)
end
function newQuest:AddToQuestList(Player)
if self.Stats == nil or next(self.Stats) == nil then return end
local PlrGui = Player.PlayerGui
local QuestsGui = PlrGui:FindFirstChild("Quests")
local QFrame = QuestsGui and QuestsGui:FindFirstChild("QuestsFrame")
local Bg = QFrame and QFrame:FindFirstChild("Bg")
if not Bg then
warn("Quest UI elements not found for player: " .. Player.Name)
return
end
local MainQuests = Bg:FindFirstChild("MainQuests")
local QuestNameLabel = MainQuests and MainQuests:FindFirstChild("QuestName")
local Frame = MainQuests and MainQuests:FindFirstChild("Frame")
local BaseStatFrame = Frame and Frame:FindFirstChild("BaseProgressFrame")
local RewardsFrame = Frame and Frame:FindFirstChild("RewardsFrame")
if not (QuestNameLabel and Frame and BaseStatFrame) then
warn("Quest UI components missing for player: " .. Player.Name)
return
end
QuestNameLabel.Text = self.Name
-- Clear previous content
for _, Child in ipairs(Frame:GetChildren()) do
if Child ~= BaseStatFrame and Child ~= RewardsFrame and Child:IsA("Frame") then
Child:Destroy()
end
end
-- Update Progress Bars
for Stat, Req in pairs(self.Stats) do
local Clone = BaseStatFrame:Clone()
local ProgLabel = Clone:FindFirstChild("ProgressLabel")
local Fill = Clone:FindFirstChild("Fill")
local QStat = Player.PhysicalStats:FindFirstChild(Stat)
if not (ProgLabel and Fill and QStat) then
warn("Quest stat or progress elements missing for player: " .. Player.Name)
return
end
ProgLabel.Text = abbreviateNumber(QStat.Value) .. "/" .. abbreviateNumber(Req) .. " " .. Stat
local Ratio = math.min(QStat.Value / Req, 1)
local tweenInfo = TweenInfo.new(1.5, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)
local tween = TweenService:Create(Fill, tweenInfo, {Size = UDim2.new(Ratio, 0, 1, 0)})
tween:Play()
QStat.Changed:Connect(function()
ProgLabel.Text = abbreviateNumber(QStat.Value) .. "/" .. abbreviateNumber(Req) .. " " .. Stat
Ratio = math.min(QStat.Value / Req, 1)
local tweenUpdate = TweenService:Create(Fill, tweenInfo, {Size = UDim2.new(Ratio, 0, 1, 0)})
tweenUpdate:Play()
end)
Clone.Name = Stat .. "ProgBar"
Clone.Visible = true
Clone.Parent = Frame
end
-- Display Class Requirement
local ClassReq = Player.leaderstats.Class.Value -- Get current class from leaderstats
local ClassRequirement = self.Class -- Assuming self.Class is the required class for the quest
-- Only display class requirement if the class is different
if ClassRequirement then
local Clone = BaseStatFrame:Clone()
local ProgLabel = Clone:FindFirstChild("ProgressLabel")
local Fill = Clone:FindFirstChild("Fill")
-- Update the progress label and fill based on the class requirement
ProgLabel.Text = "Elevate to " ..ClassRequirement
-- Set the fill ratio based on class requirement
local Ratio = (ClassReq == ClassRequirement) and 1 or 0
local tweenInfo = TweenInfo.new(1.5, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)
local tween = TweenService:Create(Fill, tweenInfo, {Size = UDim2.new(Ratio, 0, 1, 0)})
tween:Play()
-- Update the progress bar when class changes
Player.leaderstats.Class.Changed:Connect(function()
local newClass = Player.leaderstats.Class.Value
ProgLabel.Text = "Elevate to " ..ClassRequirement
local newRatio = (newClass == ClassRequirement) and 1 or 0
local tweenUpdate = TweenService:Create(Fill, tweenInfo, {Size = UDim2.new(newRatio, 0, 1, 0)})
tweenUpdate:Play()
end)
Clone.Name = "ClassReqProgBar"
Clone.Visible = true
Clone.Parent = Frame
end
local StatusReq = Player.leaderstats.Status.Value
local StatusRequirement = self.Status
if StatusRequirement then
local Clone = BaseStatFrame:Clone()
local ProgLabel = Clone:FindFirstChild("ProgressLabel")
local Fill = Clone:FindFirstChild("Fill")
-- Update the progress label and fill based on the class requirement
ProgLabel.Text = "Become a "..StatusRequirement
-- Set the fill ratio based on class requirement
local Ratio = (StatusReq == StatusRequirement) and 1 or 0
local tweenInfo = TweenInfo.new(1.5, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)
local tween = TweenService:Create(Fill, tweenInfo, {Size = UDim2.new(Ratio, 0, 1, 0)})
tween:Play()
Player.leaderstats.Status.Changed:Connect(function()
local newStatus = Player.leaderstats.Status.Value
ProgLabel.Text = "Become a "..StatusRequirement
local newRatio = (newStatus == StatusRequirement) and 1 or 0
local tweenUpdate = TweenService:Create(Fill, tweenInfo, {Size = UDim2.new(newRatio, 0, 1, 0)})
tweenUpdate:Play()
end)
Clone.Name = "StatusReqProgBar"
Clone.Visible = true
Clone.Parent = Frame
end
local TweenService = game:GetService("TweenService")
-- Display Fusion Requirement
local FusionReq = Player.leaderstats.Fusion and Player.leaderstats.Fusion.Value -- Get current fusion level from leaderstats
local FusionRequirement = self.Fusion -- Assuming self.Fusion is the required fusion level for the quest
-- Debugging output to ensure correct values
print("Current Fusion Level: " .. (FusionReq or "nil"))
print("Required Fusion Level: " .. (FusionRequirement or "nil"))
-- Only display fusion requirement if the fusion requirement is set and not nil
if FusionRequirement and FusionReq then
local Clone = BaseStatFrame:Clone()
local ProgLabel = Clone:FindFirstChild("ProgressLabel")
local Fill = Clone:FindFirstChild("Fill")
-- Update the progress label and fill based on the fusion requirement
ProgLabel.Text = "Reach Fusion Level " .. FusionRequirement
-- Calculate the fill ratio based on the fusion requirement
local Ratio = (FusionReq == FusionRequirement) and 1 or 0
-- Create and play the tween for initial progress
local tweenInfo = TweenInfo.new(1.5, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)
local tween = TweenService:Create(Fill, tweenInfo, {Size = UDim2.new(Ratio, 0, 1, 0)})
tween:Play()
-- Update the progress bar when fusion level changes
Player.leaderstats.Fusion.Changed:Connect(function()
local newFusion = Player.leaderstats.Fusion and Player.leaderstats.Fusion.Value
print("Updated Fusion Level: " .. (newFusion or "nil")) -- Debugging output
ProgLabel.Text = "Reach Fusion Level " .. (FusionRequirement or "unknown")
local newRatio = (newFusion == FusionRequirement) and 1 or 0
local tweenUpdate = TweenService:Create(Fill, tweenInfo, {Size = UDim2.new(newRatio, 0, 1, 0)})
tweenUpdate:Play()
end)
Clone.Name = "FusionReqProgBar"
Clone.Visible = true
Clone.Parent = Frame
else
print("FusionRequirement or FusionReq is nil. Progress bar will not be displayed.")
end
-- Update Rewards Frame
local TokensLabel = RewardsFrame:FindFirstChild("TokensLabel")
if not TokensLabel then
TokensLabel = Instance.new("TextLabel")
TokensLabel.Name = "TokensLabel"
TokensLabel.Size = UDim2.new(1, 0, 1, 0)
TokensLabel.BackgroundTransparency = 1
TokensLabel.TextColor3 = Color3.new(1, 1, 1)
TokensLabel.TextScaled = true
TokensLabel.Parent = RewardsFrame
end
TokensLabel.Text = "Reward: " .. abbreviateNumber(self.Rewards.Tokens) .. " Tokens"
RewardsFrame.Visible = true
end
-- Remove or hide quest UI if all quests are completed
if State == "NoMoreQuests" then
local PlrGui = Player.PlayerGui
local QuestsGui = PlrGui.Quests
local QFrame = QuestsGui.QuestsFrame
local MainQuests = QFrame.Bg.MainQuests
local Frame = MainQuests.Frame
for _, Child in ipairs(Frame:GetChildren()) do
if Child:IsA("Frame") then
Child:Destroy()
end
end
local TokensLabel = Frame:FindFirstChild("TokensLabel")
if TokensLabel then
TokensLabel:Destroy()
end
MainQuests.QuestName.Text = "More quests coming soon!"
end
return newQuest
end
return Quests