Models, Tools, Workspace, ReplicatedStorage, Cloning and Destroying

New to the forums and scripting overall in general. Sorry ahead of time if this has already been covered somewhere and I’m just missing it.
Any pointers at all are greatly appreciated.

So my goal is for a player to pickup a health potion via a Proximity Prompt. After the prompt is triggered it clones the actual Health Potion Tool from replicated storage into the players backpack.
Ideally the player would only be allowed to pick up 1 potion at each potion location. Meaning hopefully I can get the potion to stay there for other players to pickup once as well, at the same time as preventing a player who has already picked it up from seeing it again or picking it up again.

Currently with what I have learned from articles and the dev forum I have:
#1. Made a health potion model and put it into a Tool.
#2. Tool in replicated storage and regular model in workspace.
#3. Made an animation with ID defined in script/localscript.

robloxapp-20211004-1709023.wmv (1.8 MB)

Screenshot (184)

The following is a regular script within the promptAnchor

local Players = game:GetService("Players")
local ProximityPromptService = game:GetService("ProximityPromptService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local iTools = ReplicatedStorage:WaitForChild("Items_Tools")
local hpDrink = iTools:WaitForChild("HpDrink")
local drink = script.Parent.Parent.Parent

-- Detect when prompt is triggered
local function onPromptTriggered(promptObject, player)
	hpDrink:Clone().Parent = player.Backpack
	drink:Destroy()
end

-- Detect when prompt hold begins
local function onPromptHoldBegan(promptObject, player)

end

-- Detect when prompt hold ends
local function onPromptHoldEnded(promptObject, player)

end

-- Connect prompt events to handling functions
ProximityPromptService.PromptTriggered:Connect(onPromptTriggered)
ProximityPromptService.PromptButtonHoldBegan:Connect(onPromptHoldBegan)
ProximityPromptService.PromptButtonHoldEnded:Connect(onPromptHoldEnded)

As far as solutions go I tried inputting a number such as 1 to the () for clone and destroy.
I got the prompt to function properly as well as the clone and destroy but it make me pick up every other health potion in workspace…I’m confused and unfortunately feeling very frustrated with it. I don’t maybe i’m not searching for right example or I’m not understanding this process.

I don’t wish for anyone to write a whole script for me as I know that can be a pain.
If there are any resources that I missed please feel free to share.

https://developer.roblox.com/en-us/articles/Health-Pickups
https://developer.roblox.com/en-us/onboarding/creating-player-tools/1
https://developer.roblox.com/en-us/onboarding/creating-player-tools/2

Yep, the issue here is that ProximityPromptService was used instead of the individual unique proximity prompt object.

Here is the logic

ProximityPromptService.PromptTriggered–> triggers all prompts -->triggers all the potions

You can solve it by creating a proximity prompt and prompt triggered connection for each potion so you pick up each potion individually.

I also additionally suggest looking at dev forum resources to see how other people do it. Sometimes those roblox tutorials are just not enough. Like this tool giver here:

1 Like

I definitely understand what you mean by those roblox tutorials. Thank you so much! That seems to fix the issue with the duplicates.
Now that I have the Tool/Health potion, when I use it while health is < 100 then destroy the tool the health doesn’t stay…the players health goes back to what it was when before taking the potion. Not sure why it doesn’t save that health.

This is the “ToolController” localscript in the Tool

local Players = game:GetService("Players")

local player = Players.LocalPlayer

local character = player.Character
local humanoid = character:FindFirstChild("Humanoid")

local animation = Instance.new("Animation")
animation.AnimationId = "http://www.roblox.com/asset/?id=7642754676" -- CHIMPSTRONEER DrinkPotion v0.1

local animationTrack = humanoid:LoadAnimation(animation)
--animationTrack:Play()

local tool = script.Parent
local healAmount = 300

local function toolEquipped()
	print("Equipped!")
end

local function toolActivated()
	if humanoid.Health < 100 then
		local currentHealth = humanoid.Health
		local newHealth = humanoid.MaxHealth
		print("Activated!")
		animationTrack:Play()
		wait(.5)
		humanoid.Health = newHealth
		wait(.5)
		animationTrack:Stop()
		tool:Destroy()
	else
		print("No Heal Needed!")
	end
	
end

tool.Equipped:Connect(toolEquipped)
tool.Activated:Connect(toolActivated)

Yep that’s the issue, health is a property. The solution should be to use a server script instead.

That means you can access the value on the client computer, for it to update for every player it can only be changed in a server script on the servers computer.

Why?

If a player’s health or score is controlled by the server, a hacker cannot change these values in a way that will affect other players

Client-Server Model | Roblox Creator Documentation.

To access the humanoid serversided from a tool we can use the property that tools are parented within the character and so when the tool is activated you can use, tool.Parent to get the players character.

ok so i put a module script in replicated storage(not sure if that it ok)
I’m not sure what you meant by tool.Parent either i’m sorry.
I think the same thing is happening and maybe it’s because i’m not understanding the tool.Parent aspect of it right now.

local toolFunctions = {}

local Players = game:GetService("Players")
local player = Players.LocalPlayer
local character = player.Character
local backPack = player.Backpack
local healthPack = backPack:FindFirstChild("HpDrink")

function toolFunctions.drink()
	local humanoid = character:FindFirstChild("Humanoid")
	
	humanoid.Health = humanoid.MaxHealth
	healthPack:Destroy()
	
end

return toolFunctions

Then changed the localscript a little. It is still doing the same thing. Heals the player, then their health returns to what it was previously.

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local ToolUsage = require(ReplicatedStorage:WaitForChild("ToolUsage"))

local player = Players.LocalPlayer

local animation = Instance.new("Animation")
animation.AnimationId = "http://www.roblox.com/asset/?id=7642754676" -- CHIMPSTRONEER DrinkPotion v0.1


--animationTrack:Play()

local tool = script.Parent
local healAmount = 300
--local canHeal = true

local function toolEquipped()
	print("Equipped!")
end

local function toolActivated()
	
	local character = player.Character
	local humanoid = character:FindFirstChild("Humanoid")
	local animationTrack = humanoid:LoadAnimation(animation)
	
	if humanoid.Health < 100 then
		--canHeal = false
		local currentHealth = humanoid.Health
		local newHealth = humanoid.MaxHealth
		print("Heal Me Please!")
		animationTrack:Play()
		wait(1)
		ToolUsage.drink()
		animationTrack:Stop()
		--canHeal = true
	else
		print("No Heal Needed!")
	end
	
end

tool.Equipped:Connect(toolEquipped)
tool.Activated:Connect(toolActivated)

Sorry forgot to add that it isn’t giving any errors either. is that because everything is happening properly but something I’m missing is causing the health not to save/stick to the humanoid health property?

Seems like you didn’t understand the difference between client and server.

So here is the script.

Replace the local script with this server script.

--Needs to be a server script in order for the health changes to be "saved"
local animation = Instance.new("Animation")
animation.AnimationId = "http://www.roblox.com/asset/?id=7642754676" -- CHIMPSTRONEER DrinkPotion v0.1

local animationTrack

local tool = script.Parent
local healAmount = 300

local function toolEquipped()
	print("Equipped!")
	local character = tool.Parent -- access the character from here from a server script
	local humanoid = character:FindFirstChild("Humanoid")
	animationTrack = humanoid:LoadAnimation(animation)

end

local function toolActivated()
	local character = tool.Parent -- access the character from here from a server script
	local humanoid = character:FindFirstChild("Humanoid")

	if humanoid.Health < 100 then
		local currentHealth = humanoid.Health
		local newHealth = humanoid.MaxHealth
		print("Activated!")
		animationTrack:Play()
		wait(.5)
		humanoid.Health = newHealth
		wait(.5)
		animationTrack:Stop()
		tool:Destroy()
	else
		print("No Heal Needed!")
	end
	
end

tool.Equipped:Connect(toolEquipped)
tool.Activated:Connect(toolActivated)

So with that script, I get this error. I’m assuming I need define the specific health potion then?

20:11:59.457  Equipped is not a valid member of ServerScriptService "ServerScriptService"  -  Server - Script:38
  20:11:59.457  Stack Begin  -  Studio
  20:11:59.457  Script 'ServerScriptService.Script', Line 38  -  Studio - Script:38
  20:11:59.457  Stack End  -  Studio

Let’s analyze the error.
The error is here:

tool.Equipped:Connect(toolEquipped)

member means that we tried to access a function or property that doesn’t exist meaning .Equipped doesn’t exist for the tool.

Looking further back tool was defined as:

local tool = script.Parent

This menas that the script is expecting this kind of hierarchy where the script (I refer to it as a server script because this type of script is ran from the server) is inserted inside the tool seen in the image below, such that when we .Parent we can get the tool instance:

image

However you have inserted it ServerScriptService which is not a tool and hence the error.

1 Like

Thank you so much, I understand now. Was making it way too difficult for myself.
Marking your last reply as the solution to this problem I was having. Question I have now mainly is if tools can be stacked in the backpack? If the player has multiple health potion tools it currently just lines them up taking a huge amount of space in the default backpack slots. Any articles anyone knows of for Tool Stacking?

1 Like

Nope, tool stacking is an entirely different system one has to make themselves.

A simpler method for tools with the same item is to simply detect if the character has the tool or it’s in their backpack (Tools are either parented within the character or backpack if someone has them)

Then use an attribute or intValue to communciate to the tool script that the number of potions has been +1 ed, then instead of destroying the tool just -1 from this value until 0 where it is then destroyed.

There’s a lot of ways but thats the gist of the logic. You can use another method of communication instead of attributes like signals and custom events if you want to be more advanced.

1 Like