How to make an advanced key system

So I want to make a door which is locked and only police can open it. But I also want a lockpick criminals can use to open the door. The door uses proximity prompts and I want a police officer to open the door just like unlocked doors (a hold duration of 0). But if a criminal has a lockpick I want the hold duration to change to 5.

The issue is I don’t know how to do this detection because the script is global so I cant check if a character has lockpicks BEFORE they start triggering the prompt.

I’ve included my failed attempts in the script below but other than that I’ve looked up this subject but there is nothing like this with proximity prompts.

Here is the one script and a screenshot of the doors children:

local TweenService = game:GetService("TweenService")
local doorModel = script.Parent.Parent.Parent.Parent
local Open = script.Parent.Parent.Parent.Open
local Close = script.Parent.Parent.Parent.Close

local Speed = doorModel.DoorSpeed.Value

script.Parent.HoldDuration = 0
local deBounce = false

script.Parent.PromptShown:Connect(function(inputTypem) -- Here I was hoping that this would give me the player so I could
														-- get the character and change the Hold Duration accordingly
	
end)

script.Parent.Triggered:Connect(function(player)
	if doorModel.Locked.Value and player.Team ~= game.Teams.Police then --This was my failed attempt...
		script.Parent.ActionText = "Locked"
		if player.Character:FindFirstChild("LockPicks") then
			script.Parent.HoldDuration = 5
			
		end
	end

	
	if deBounce then return end
	deBounce = true

	local cframe = doorModel.Hinge.CFrame * CFrame.Angles(0, math.rad(90), 0)

	if script.Parent.ActionText == "Open" then
		Open.TimePosition = 0.7
		Open:Play()
		cframe = doorModel.Hinge.CFrame * CFrame.Angles(0, math.rad(90), 0)
		script.Parent.ActionText = "Close"
	elseif script.Parent.ActionText == "Close" then
		Close.TimePosition = 0.2
		Close:Play()
		cframe = doorModel.Hinge.CFrame * CFrame.Angles(0, math.rad(-90), 0)
		script.Parent.ActionText = "Open"
	else
		return
	end


	local doorTween = TweenService:Create(doorModel.Hinge, TweenInfo.new(Speed, Enum.EasingStyle.Quad), {CFrame = cframe})

	doorTween:Play()
	wait(Speed)
	deBounce = false
end)

2 Likes

Maybe approach it from a different side. How about getting into a localScript, checking the player’s team, and changing the proximityPrompt (or a for i, v in ipairs do loop for more proximityPrompts) accordingly, and you’re all set. Change the duration for criminals, and check for lockpicks in hand before proceeding to open the door with the ["ProximityPrompt"].InputBegan function, which also gets you the playerWhoTriggered parameter, and for officers, change it’s hold duration time to 0.

2 Likes

Do the detection part in a localscript. Then fire a remoteevent and do the tweening in a global script hence the tweening is visible to everyone.

1 Like

Besides, LocalScripts have game.Players.LocalPlayer, so even the ["ProximityPrompt"].PromptShown way is possible. (with proper RemoteEvents of course, as @RobloxPlayer_9384 stated earlier)

1 Like

Ill try it in a local script now, I’ll let you know how it goes. or if I have anymore questions.

@RobloxPlayer_9384 @BackSpaceCraft
Since the game has multiple doors how would I use one local script and detect whenever any of the prompts are visible?

If you meant ALL doors:

for i, door in ipairs(workspace:GetDescendants()) do
     if door.Name == ["Door's name"] then
          -- proceed to do stuff
     end
end

If you meant specific doors in-game:

  • If it’s possible, you could put all the doors into a folder, and do an ipairs loop there.
  • If it doesn’t tamper with your other scripts, you could name the doors to a specific name, and do stuff with it using the code block above.
  • (Most efficient in my opinion) You could insert a BoolValue into the door (Any value will do), name it something special and then check for its existence with the code block above.
1 Like

Just did everything and it works!

The only thing is that proximity prompts only reset once you walk away from them so you that the Gui can close and a new one can appear with the changes (hold duration).
I’m just wondering if there is a way around that or not.

So you mean it still uses the last set hold duration? That’s odd, the proximityPrompt should update automatically. You do use these with RemoteEvents, right?

Perhaps set it disabled for a short time and re-Enable? That should do it anyway.

1 Like

The proximity prompt updates, and the remote events are fine, But it only updates once you walk away and then come back to it so the gui can reset.

Perhaps do:

for i, prompt in ipairs(workspace:GetDescendants()) do
	if prompt:IsA("ProximityPrompt") then
		prompt.Changed:Connect(function()
			prompt.Enabled = false
			wait()
			prompt.Enabled = true
		end)
	end
end
1 Like

I figured it out thanks,
For people looking for solution:
Basically Make a local script and change the duration there based on if the player has a lockpick or is a police officer.

local DoorEvent = game.ReplicatedStorage:WaitForChild("Events"):WaitForChild("DoorEvent") -- Get remote event

local function Doors()
	for i, door in ipairs(workspace:GetDescendants()) do
		if door:IsA("Model") and door.Name == "LockedDoor" then
			local Prompt = door:WaitForChild("Door"):WaitForChild("Door"):WaitForChild("Attachment"):WaitForChild("ProximityPrompt")
			local Locked = door:WaitForChild("Door"):WaitForChild("Locked")
			local Character = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
			
			Prompt.Enabled = false --Hide the prompt
			
			if Locked.Value and game.Players.LocalPlayer.Team ~= game.Teams.Police then --Check if Police and locked
				Prompt.HoldDuration = 60
				if Character:FindFirstChild("LockPicks") then
					Prompt.HoldDuration = 5
					Prompt.Enabled = true --Show prompt and set Duration if lockpicks
				end
				print(Prompt.HoldDuration)
			else
				Prompt.HoldDuration = 0
				Prompt.Enabled = true --Show prompt and set Duration if police
			end

			Prompt.Triggered:Connect(function(player)
				DoorEvent:FireServer(door.Name) --Tell the server to open/close the door Globaly
											--Also Send the Door's name so the script knows
											--Which door to open
			end)
		end
	end
end

script.Parent.ChildAdded:Connect(function(child) --Check For LockPicks
	if child.Name == "LockPicks" then
		Doors()
	end
end)
script.Parent.ChildRemoved:Connect(function(child) --Check if LockPicks were hidden
	if child.Name == "LockPicks" then
		Doors()
	end
end)

Doors()

Then fire a remote event to a serverScript which tells it to open the door, you can do that however you want bust just do it inside this:

local DoorEvent = game.ReplicatedStorage:WaitForChild("Events"):WaitForChild("DoorEvent")

local deBounce = false

DoorEvent.OnServerEvent:Connect(function(player, name)
    if script.Parent.Name ~= name then return end
	if deBounce then return end
	deBounce = true
        --Open/Close door here
	deBounce = false
end)

Thanks to @BackSpaceCraft and @RobloxPlayer_9384 for the help!

Just updated with a bug fix, all doors were opening and I finally found s simple solution: Send the name to the door to make sure its the right one.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.