Table inside table inside table

So I have this touched event which needs to only beable to be fired once for each player.

dictionary = {}

local wallName = wall.Name
local stageName = wall.Parent.Name
				
if not dictionary[player.Name][stageName][wallName] then -- this is in a touched event
    dictionary[player.Name] = stageName
    dictionary[player.Name][stageName] = wallName
elseif dictionary[player.Name][stageName][wallName] then return end

I’m trying to make the player unable to touch the same part twice

but it doesnt work, can someone help me?

2 Likes

is dictionary = {} in the touch event? if so, the dictionary may be resetting each time the part is touched

Are you using a touched event? Is progress being saved? Can they touch the part again next time they rejoin?

if you are using a touched event and want them to be able to touch the part again he next time they rejoin you could use Once

But if you’re not using the touched event then idk

thats not the problem, then problem is: attempt to index nil with ‘Stage1’, the error is at the if statment line

I can’t put the tables into the dictionaries

Because dictionary[playerName] is nil, it can’t be indexed further. Remove the other checks and just do “if not dictionary[playerName] then”

I made this now:

if not dictionary[player.Name] then
					dictionary[player.Name] = stageName
					dictionary[player.Name][stageName] = wallName
				elseif dictionary[player.Name] and not dictionary[player.Name][stageName] then
					dictionary[player.Name] = stageName
					dictionary[player.Name][stageName] = wallName -- it errors at this line with: attempt to index string with 'Stage1'
				elseif dictionary[player.Name][stageName] and not dictionary[player.Name][stageName][wallName] then
					dictionary[player.Name][stageName] = wallName
				elseif dictionary[player.Name][stageName][wallName] then return end

the dictionary should look like

dictionary = {[“playerName”] = {[“Stage1”] = “wallName”}}

Right now you’re doing

dictionary = { [playerName] = stageName }

It would be easier to do

dictionary[playerName] = {stageName, wallName}

where dictionary[playerName][1] is the stage name and dictionary[playerName][2] is the wall name.

Will this also work if I have multiple stages and multiple walls per stage?

Yeah, if you change it to

dictionary = {[playerName] = {{stageName}, {wallName}}}

then table.add to dictionary[playerName][1] or [2].

I don;t understand what youre saying. If I were to add to dictionary[playerName][1], wont it look like this

dictionary = {[playerName] = {{stageName} = {wall2Name}, {wallName}}}

isn’t there a way for me to just:

dictionary = {[playerName] = {[stageName] = {wallName, wall2Name, wall3Name},[stage2Name] = {wallName, wall2Name, wall3Name}}}

but then make that with a script?

dictionary = {}

local wallName = wall.Name
local stageName = wall.Parent.Name
--dictionary[player.Name] can store both stageName and wallName keys, so you should do that instead of storing dictionaries inside a dictionary inside a dictionary, would optimize more memory that way.
if not dictionary[player.Name][wallName] then -- this is in a touched event
    dictionary[player.Name].stageName = stageName
    dictionary[player.Name].wallName = wallName
elseif dictionary[player.Name][wallName] then return end

I believe this would also work, without the use of 3D Tables (a.k.a table inside table inside table). If this doesn’t work otherwise, could you send the full script for more context?

What I’m trying to do is if the player is not in the dictironary add the player and the stage and the wall. Else if the player is but the stage isn’t then add the stage and the wall. else if only the wall is left, then add the wall, but if everything is there break the touched event.

local luckWalls = workspace:WaitForChild("Map"):WaitForChild("LuckWalls")
local stageSpawns = workspace:WaitForChild("Map"):WaitForChild("StageSpawns")
local luckWallRemote = game:GetService("ReplicatedStorage"):WaitForChild("LuckWallRemote")

local dictionary = {}

for i,v in pairs(luckWalls:GetDescendants()) do
	if v.ClassName == "Part" and v.Name ~= "EndPart" and v.Name ~= "EntryPart" or v.ClassName == "BasePart" and v.Name ~= "EndPart" and v.Name ~= "EntryPart" then
		local wall = v
		
		local digits = {}
		
		wall.SurfaceGui.TextLabel.Text = wall.Name

		for occurrence in (wall.Name):gmatch("%d+") do
			table.insert(digits, tonumber(occurrence))
		end
		
		wall.Touched:Connect(function(hit)
			local player = game.Players:GetPlayerFromCharacter(hit.Parent)
			if player then
				local wallName = wall.Name
				local stageName = wall.Parent.Name
				print(dictionary)
				if not dictionary[player.Name][wallName] then -- this is in a touched event
					dictionary[player.Name].stageName = stageName
					dictionary[player.Name].wallName = wallName
				elseif dictionary[player.Name][wallName] then return end
				
				print(dictionary)
				
				if math.floor(digits[2] / player.leaderstats.Luck.Value) <= 1 then
					if player.leaderstats.Luck.Value - digits[2] <= 0 then
						player.leaderstats.Luck.Value -= digits[2]
					else
						player.leaderstats.Luck.Value = 0
					end
					
					-- send message to client
					luckWallRemote:FireClient(player,wall)
				else
					if player.leaderstats.Luck.Value - digits[2] <= 0 then
						player.leaderstats.Luck.Value -= digits[2]
					else
						player.leaderstats.Luck.Value = 0
					end
					
					local randomNumber = math.random(digits[1],math.floor(digits[2] / player.leaderstats.Luck.Value))
					
					if randomNumber == digits[1] then
						-- teleport back
						player.Character.HumanoidRootPart.CFrame = stageSpawns:FindFirstChild(wall.Parent.Name.."Spawn")
					end
				end
			end
		end)
	elseif v.Name == "EndPart" then
		local endPart = v
		
		if endPart.Parent.Name == "Stage1" then -- this is the current stage
			endPart.Touched:Connect(function(hit)
				local player = game.Players:GetPlayerFromCharacter(hit.Parent)
				if player then
					player.leaderstats.Wins.Value += 1 -- change this to amount of wins at the current stage
					
					for i,v in pairs(dictionary[player.Name][endPart.Parent.Name]) do
						v = nil
					end
				end
			end)
		end
	elseif v.Name == "EntryPart" then
		v.Touched:Connect(function(hit)
			local player = game.Players:GetPlayerFromCharacter(hit.Parent)
			if player then
				luckWallRemote:FireClient(player,nil,nil,v.Parent.Name)
			end
		end)
	end
end

this is the whole script

I see that dictionary[player.Name] is not defined beforehand. Which would cause an Attempt to index nil with key error. I believe the solution is to define the player’s dictionary before the if statements. Here’s what the script should look like:

dictionary = {}

local wallName = wall.Name
local stageName = wall.Parent.Name
if dictionary[player.Name] == nil then
      dictionary[player.Name] = {}
end
if not dictionary[player.Name][stageName][wallName] then -- this is in a touched event
    dictionary[player.Name][stageName] = stageName
    dictionary[player.Name][stageName][wallName] = wallName
elseif dictionary[player.Name][stageName][wallName] then return end

Please tell me whether this solution works or not.

I would do physical folders in the player’s folder in Players for simplicity’s sake. A folder for stages, with folders for each stage, with the parts for each stage.

The problem is that stageName doesnt exist in the if statement line

Stage name needs to be added before the if statment

also the table now looks like this:

["pasje1312"] = {["Stage1"] = "Stage1"}

and I changed the dictionary to:

if dictionary[player.Name] == nil then
					dictionary[player.Name] = {}
				end
				if dictionary[player.Name][stageName] == nil then -- this is in a touched event
					dictionary[player.Name][stageName] = stageName
					dictionary[player.Name][stageName][wallName] = wallName
				elseif dictionary[player.Name][stageName] and dictionary[player.Name][stageName][wallName] == nil then
					dictionary[player.Name][stageName][wallName] = wallName
				elseif dictionary[player.Name][stageName][wallName] then return end

but there still the error: attempt to index string with ‘myWallName’

I only put the script just like how you put it at the beginning.

Try removing the return keyword and see if it ends.