This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Jakos's profile picture

Table returning nil

Started by Jakos, 18 August 2014 - 10:47 AM
Jakos #1
Posted 18 August 2014 - 12:47 PM
I started to make a game yesterday, but I have a problem…
I've made 5 functions. "genStrip" and "genWorld" generate a random 100x100 world, "makeTile" creates a tile kind with the desired properties and "renderTile" and "renderWorld" draws a tile acording to the player position (so I made a temporary value for this).
The problem is that when I use renderWorld it says that the world table is nil.

Code:
Spoiler
world={}
world.config={} --[1]=difficulty [2]=time [3]=season
world.tiles={}
world.tiles.blocks={} -- works like [(layer)][(y)][(x)]=[tile id]
world.tiles.blocks[0]={}
world.tiles.blocks[1]={}
world.tiles.blocks[2]={}
world.tiles.blocks[3]={}
world.tiles.blocks[4]={}
world.tiles.objects={} -- works like [(layer)][(y)][(x)]=[object id]
world.player={}
world.player.inv={} --works like [(slot number)][1]=item id ,[(slot number)][2]=item durability ,[(slot number)][3]=item ammount
world.player.stats={} --[1]=health [2]=hunger [3]=thirst [4][1]=xpos [4][2]=ypos [5]=score [6]=layer
tiles={}
items={}
objects={}
monsters={}
--Tile config:
function makeTile(id,name,char,bgcolor,txtcolor,durability,isafloor,specialtype,toolneeded,droppedid,dropsitem,haschance,chancedroppeditem,canbedigged,idwhendigged,chanceditemwhendigged,whendiggeditemid)
tiles[id]={}
tiles[id][1]=name
if char==nil then
tiles[id][2]=" "
else
tiles[id][2]=char
end
tiles[id][3]=bgcolor
tiles[id][4]=durability --make this a random value or even nil if the "toolneeded" is 0 (indistructible)
tiles[id][5]=isafloor
tiles[id][6]=specialtype
tiles[id][7]=toolneeded --0:cant be destroyed 1:hands and all others 2:pickaxe 3:shovel
if dropsitem==true then
tiles[id][8]=items[droppedid]
else
tiles[id][8]=tiles[droppedid]
end
if haschance==true then
tiles[id][9]=items[chancedroppeditem]
else
tiles[id][9]=nil
end
tiles[id][10]=txtcolor
if chanceditemwhendigged==true then
tiles[id][11]=items[whendiggeditemid]
else
tiles[id][11]=nil
end
end
makeTile(0,"Air",nil,colors.lightBlue,colors.lightBlue,0,false,0,0,nil,false,false,nil,false,nil,false,nil)
makeTile(1,"Grass","'",colors.lime,colors.green,0,true,1,3,2,false,false,nil,true,2,true,7)
makeTile(2,"Dirt","'",colors.brown,colors.lightGray,0,true,1,3,2,false,false,nil,true,21,false,nil)
makeTile(3,"Stone","L",colors.gray,colors.lightGray,0,false,0,2,1,true,true,2,false,nil,false,nil)
makeTile(4,"Flowers","*",colors.lime,colors.yellow,0,true,2,1,4,false,false,nil,true,1,true,7)
makeTile(5,"Tree","O",colors.lime,colors.green,0,false,0,1,3,true,true,8,false,nil,false,nil)
makeTile(6,"Water","~",colors.blue,colors.lightBlue,0,true,3,0,nil,false,false,nil,false,nil,false,nil)
makeTile(7,"Iron","*",colors.gray,colors.brown,1,false,0,2,4,true,false,nil,false,nil,false,nil)
makeTile(8,"Gold","*",colors.gray,colors.yellow,2,false,0,2,5,true,false,nil,false,nil,false,nil)
makeTile(9,"Gem","*",colors.gray,colors.pink,3,false,0,2,6,true,false,nil,false,nil,false,nil)
makeTile(10,"Lava","~",colors.orange,colors.red,0,true,4,0,nil,false,false,nil,false,nil,false,nil)
makeTile(11,"Obsidian","L",colors.purple,colors.black,4,false,0,2,1,true,true,2,false,nil,false,nil)
makeTile(12,"Cloud",nil,colors.white,colors.white,0,true,0,0,nil,false,false,nil,false,nil,false,nil)
makeTile(13,"Spikes","*",colors.white,colors.lightGray,4,false,0,2,nil,false,false,nil,false,nil,false,nil)
makeTile(14,"Upstair","^",colors.lightGray,colors.gray,0,true,5,0,nil,false,false,nil,false,nil,false,nil)
makeTile(15,"Downstair","V",colors.lightGray,colors.gray,0,true,6,0,nil,false,false,nil,false,nil,false,nil)
makeTile(16,"Farmland","=",colors.brown,colors.lightBlue,0,true,7,0,nil,false,false,nil,true,2,false,nil)
makeTile(17,"FarmSeeds","=",colors.brown,colors.lime,0,true,8,0,7,true,false,nil,true,16,false,nil)
makeTile(18,"FarmWheat","W",colors.brown,colors.yellow,0,true,0,0,9,true,false,nil,true,16,true,9)
makeTile(19,"Hole","O",colors.brown,colors.black,0,false,9,0,nil,false,false,nil,false,nil,false,nil)
makeTile(20,"Sand","~",colors.yellow,colors.yellow,0,true,10,3,20,false,false,nil,true,1,false,nil)
makeTile(21,"Cactus","O",colors.yellow,colors.green,0,false,0,1,21,false,false,nil,false,nil,false,nil)
--Internal
function genStrip(layer,y)
world.tiles.blocks[layer][y]={}
for x = 1, 100 do
if layer==0 then
local terrain=math.random(1,3)
elseif layer==1 then
local terrain=math.random(1,7)
elseif layer==2 then
local terrain=math.random(1,3)
elseif layer==3 then
local terrain=math.random(1,4)
elseif layer==4 then
local terrain=math.random(1,4)
end
if layer==0 then
if terrain==1 then
world.tiles.blocks[layer][y][x]=0
elseif terrain==2 then
world.tiles.blocks[layer][y][x]=12
elseif terrain==3 then
world.tiles.blocks[layer][y][x]=13
end
elseif layer==1 then
if terrain==1 then
world.tiles.blocks[layer][y][x]=1
elseif terrain==2 then
world.tiles.blocks[layer][y][x]=3
elseif terrain==3 then
world.tiles.blocks[layer][y][x]=4
elseif terrain==4 then
world.tiles.blocks[layer][y][x]=5
elseif terrain==5 then
world.tiles.blocks[layer][y][x]=6
elseif terrain==6 then
world.tiles.blocks[layer][y][x]=20
elseif terrain==7 then
world.tiles.blocks[layer][y][x]=21
end
elseif layer==2 then
if terrain==1 then
world.tiles.blocks[layer][y][x]=1
elseif terrain==2 then
world.tiles.blocks[layer][y][x]=3
elseif terrain==3 then
world.tiles.blocks[layer][y][x]=7
end
elseif layer==3 then
if terrain==1 then
world.tiles.blocks[layer][y][x]=1
elseif terrain==2 then
world.tiles.blocks[layer][y][x]=3
elseif terrain==3 then
world.tiles.blocks[layer][y][x]=8
elseif terrain==4 then
world.tiles.blocks[layer][y][x]=6
end
elseif layer==4 then
if terrain==1 then
world.tiles.blocks[layer][y][x]=1
elseif terrain==2 then
world.tiles.blocks[layer][y][x]=3
elseif terrain==3 then
world.tiles.blocks[layer][y][x]=9
elseif terrain==4 then
world.tiles.blocks[layer][y][x]=10
end
end
end
end
function genWorld()
for currenty = 1,100 do
genStrip(0,currenty)
genStrip(1,currenty)
genStrip(2,currenty)
genStrip(3,currenty)
genStrip(4,currenty)
end
end
function renderTile(layer,y,x)
local rid=world.tiles.blocks[layer][y][x]
term.setTextColor(tiles[rid][10])												   <<<<<<<<<<<<<<<<<<<<<<<<--The program crashes here
term.setBackgroundColor(tiles[rid][3])
if tiles[rid][2]==nil then
term.write(" ")
else
term.write(tiles[rid][2])
end
end
function renderWorld(playerlayer,playery,playerx)
for y = 0, 17 do
local rendery=(playery-8)+y
for x = 0, 49 do
local renderx=(playerx-24)+x
renderTile(playerlayer,rendery,renderx)
end
end
end
genWorld()
renderWorld(1,10,10)

Error:
minicraft:156: attempt to index ? (a nil value)

Help is apreciated,
Jakos

Edit:RickiHN nailed
Edited by
RickiHN #2
Posted 18 August 2014 - 03:04 PM
Pls put it in a code block and use indentation. That is almost impossible to read :P/>
Also pls mark of the 156th line for people as they don't get line numbers(and you don't expect them to count down all 156 lines to find the problem).
Edited on 18 August 2014 - 01:06 PM
Cranium #3
Posted 18 August 2014 - 05:36 PM
I counted, and line 156 is an else… You sure that's correct?
Bomb Bloke #4
Posted 18 August 2014 - 10:47 PM
This bit here's the problem:

if layer==0 then
local terrain=math.random(1,3)
elseif layer==1 then
local terrain=math.random(1,7)
elseif layer==2 then
local terrain=math.random(1,3)
elseif layer==3 then
local terrain=math.random(1,4)
elseif layer==4 then
local terrain=math.random(1,4)
end

Defining "terrain" as local to the if blocks means it gets wiped as soon as they finish. Use a forward declaration instead:

local terrain
if layer==0 then
terrain=math.random(1,3)
elseif layer==1 then
terrain=math.random(1,7)
elseif layer==2 then
terrain=math.random(1,3)
elseif layer==3 then
terrain=math.random(1,4)
elseif layer==4 then
terrain=math.random(1,4)
end
Edited on 18 August 2014 - 08:49 PM
Jakos #5
Posted 18 August 2014 - 11:26 PM
Sorry for not replying i've been very busy… *cough* playing *cough*… but I changed the code but I still got the same problem :/
minicraft:157: attempt to index ? (a nil value)
Bomb Bloke #6
Posted 18 August 2014 - 11:46 PM
In that case, might I suggest 1) posting the new version of your code and 2) marking out the line throwing the error.
Jakos #7
Posted 19 August 2014 - 12:14 AM
I just replaced the code that you said.
Anyway its late so im going to sleep now.
Thx for the help tho :D/>
Dragon53535 #8
Posted 19 August 2014 - 04:41 AM
Correct me if i'm wrong, but you defined

tiles[id][2]
but not
tiles[rid][2]
I was wrong, you defined rid in the function calling the error.

Testing your code now and attempting to find the problem, i'm getting an error though when you set the textcolor and background color.

Your problem is that rid is returning nil itself. So that means that whatever you're using for filing the world is not working.

I found your problem, and boy is it a doozy.
First thing, when generating your world you use

for x = 1, 100 do
if layer==0 then
local terrain=math.random(1,3) -- exists only in here
elseif layer==1 then
local terrain=math.random(1,7) -- ^^
elseif layer==2 then
local terrain=math.random(1,3) -- ^^
elseif layer==3 then
local terrain=math.random(1,4) -- ^^
elseif layer==4 then
local terrain=math.random(1,4) -- ^^
end
THIS IS INCORRECT. Each local terrain disappears when the if's are over, the way you want to do it is by defining terrain before the if's as such

for x = 1, 100 do
local terrain -- the rest of your code exists inside this for loop, so will terrain
if layer==0 then
terrain=math.random(1,3) --# this assumes you're talking about the terrain above, and will set the above's value to be it's own.
elseif layer==1 then
terrain=math.random(1,7)
elseif layer==2 then
terrain=math.random(1,3)
elseif layer==3 then
terrain=math.random(1,4)
elseif layer==4 then
terrain=math.random(1,4)
end
Secondly, at where the error happens, and this one is going to be fun to fix, rid is returning nil for the first, 8 or so times since you're creating negatives at

for x = 0, 49 do
local renderx=(playerx-24)+x -- x starts at 10, this makes it -14, you have not made a block for this spot.
and FINALLY your big error that you're getting, attempt to index a nil value.

function renderTile(layer,y,x)
local rid=world.tiles.blocks[layer][y][x]
term.setTextColor(tiles[rid][10])
term.setBackgroundColor(tiles[rid][3])
if tiles[rid][2]==nil then
term.write(" ")
else
term.write(tiles[rid][2])
end
end
Since for the first few blocks rid is going to == nil, you're not able to get information out of rid being nil, so that means that tiles[rid][10] is nil, now this will not happen if you fix your math before, so this code area will work as intended once you fix that issue. Secondly, using term.write() is not good as term.write() does not text wrap, however write() does so you should use write instead of those term.write's.

So, that is why your code is messed up, because you did not allow a variable to continue on in the first code block, you did your math wrong, and you used term.write that doesn't word wrap. Is there anything else you need help with?

PS. I believe that you're making too many lines that cannot be read on screen at one time, thus showing you the ground.
Edited on 19 August 2014 - 04:40 AM
Jakos #9
Posted 19 August 2014 - 12:12 PM
Thx for the help guys but the problem is still there. I made some gates in the math so that the variables dont get negative but its still there :(/> . I'm gonna rewrite the entire code,so… don't waste more time with this.
Anyway thx for the help :)/>

Edit: Could you lock this thread admin?
Edited on 19 August 2014 - 10:12 AM
theoriginalbit #10
Posted 19 August 2014 - 12:38 PM
we generally don't lock threads in Ask a Pro unless under certain circumstances. this is primarily just incase you have further problems with this and wish to come back for more advice, you can simply just continue the discussion here.
Dragon53535 #11
Posted 19 August 2014 - 05:32 PM
That's odd, i tested your code on my single player world and it worked fine, perhaps it's the gates you made? The easiest way to just have the world generate the way you want would be just to make it go from -100 to 100 or to test it you could just set that line to be just -9 instead of - 24
Edited on 19 August 2014 - 03:36 PM