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

Trouble placement of array variables and functions

Started by aceyo369, 17 August 2014 - 03:18 PM
aceyo369 #1
Posted 17 August 2014 - 05:18 PM
Although i encounter a common error here which is line 21, attempt to index ? (a nil value) but there is something that make this error even more complicated, which is the different placement of array and functions that correspond to each other. I need help to give my tips on how to arrange my codes so that i won't get the error.

The error occurs when i want to call a function that seems to be nil…

This is the code:(UNDERLINED IS WHERE ERROR OCCURS)

local select = 1
local running = true

local function clear()
term.clear()
term.setCursorPos(1,1)
end

local function printMenu(menustate)
clear()
for i = 1, #menustate do
if i == select then
print(">"..menustate.opt)
else
print(menustate.opt)
end
end
end

local function control()
changeState("control")
end

local function keyHandler(menustate)
event, key = os.pullEvent()
if key == 200 and select > 1 then
select = select - 1
elseif key == 208 and select < #menustate then
select = select + 1
elseif key == 28 then
menustate.action()
end

end

local menu = {
["main"] = {
[1] = {opt = "Control", action = control},
[2] = {opt = "Command", action = command},
[3] = {opt = "Exit", action = exit}
},
["control"] = {
[1] = {opt = "Lights", action = light},
[2] = {opt = "Door", action = door}
},
["command"] = {},
["lights"] = {}
}

local menustate = menu["main"]

local function changeState(newstate)
menustate = menu[newstate]
end

while true do
printMenu(menustate)
keyHandler(menustate)
end
Edited on 17 August 2014 - 04:05 PM
RickiHN #2
Posted 17 August 2014 - 06:22 PM
What exactly is this function "changeState" and where is it defined? And why are you feeding it the string "("control")"
aceyo369 #3
Posted 17 August 2014 - 06:33 PM
local menu = {
["main"] = {
[1] = {opt = "Control", action = control},
[2] = {opt = "Command", action = command},
[3] = {opt = "Exit", action = exit}
},
["control"] = {
[1] = {opt = "Lights", action = light},
[2] = {opt = "Door", action = door}
},
["command"] = {},
["lights"] = {}
}

local function changeState(newstate)
menustate = menu[newstate]
end

changeState("control") simply change the menustate to a control menu
KingofGamesYami #4
Posted 17 August 2014 - 07:26 PM
Try defining your functions before calling them.
aceyo369 #5
Posted 17 August 2014 - 07:45 PM
So if i define the function before calling for them, there will be another error called as it is calling for menu["control"] but the variable is later then defined. So to make everyone clear, i have an issue for the defining of variables and functions that corresponds with each other, one comes after another still gives error…

These four parts causes the problem, i need better ways to arrange them…

local menu = {
["main"] = {
[1] = {opt = "Control", action = control},
[2] = {opt = "Command", action = command},
[3] = {opt = "Exit", action = exit}
},
["control"] = {
[1] = {opt = "Lights", action = light},
[2] = {opt = "Door", action = door}
},
["command"] = {},
["lights"] = {}
}

local function changeState(newstate)
menustate = menu[newstate]
end

local function control()
changeState("control")
end

local function keyHandler(menustate)
event, key = os.pullEvent()
if key == 200 and select > 1 then
select = select - 1
elseif key == 208 and select < #menustate then
select = select + 1
elseif key == 28 then
menustate[select].action()
end
Edited on 17 August 2014 - 05:47 PM
KingofGamesYami #6
Posted 17 August 2014 - 07:51 PM
Fixed it for you:

local menu = {
	["main"] = {
		[1] = {opt = "Control", action = control},
		[2] = {opt = "Command", action = command},
		[3] = {opt = "Exit", action = exit}
	},
	["control"] = {
		[1] = {opt = "Lights", action = light},
		[2] = {opt = "Door", action = door}
	},
	["command"] = {},
	["lights"] = {},
}

local function changeState(newstate)
	menustate = menu[newstate]
end

local function control()
	changeState("control") 
end

local function keyHandler(menustate)
	event, key = os.pullEvent()
	if key == 200 and select > 1 then
		select = select - 1
	elseif key == 208 and select < #menustate then
		select = select + 1
	elseif key == 28 then
		menustate[select].action()
	end
end
The issue: you were missing an end. It was easy to see after properly indenting your code. Also I believe there was a comma missing.
aceyo369 #7
Posted 17 August 2014 - 07:58 PM
It is still not fixed, now the error occurs at the menustate[select].action(), attempt to call nil
MKlegoman357 #8
Posted 17 August 2014 - 10:06 PM
In Lua, you have to first define any variables (functions are variables too) before you can use them, but if you really need to use a variable before you can define it (and don't worry, there are a lot of cases where this kind of thing is needed) you can forward-define the variable like so:


local foo --// Define the variable, it's going to be nil for now

local function bar ()
  print(foo + 2) --// We use the variable "foo" assuming it is a number, even though it's still nil
end

foo = 3 --// We define the variable later

bar() -->> 5

Note that you do not have to do this if you are using global variables, but using them is a bad habit and you should always, when possible, use local variables.
KingofGamesYami #9
Posted 17 August 2014 - 11:20 PM
It is still not fixed, now the error occurs at the menustate[select].action(), attempt to call nil
Uhm… Please post the full code. Some of the actions are *not* defined here, which might be the problem.

Edit: I'm not sure if this is related to your question or not, but this may help you… I wrote a quick little "menu" code that is pretty simple to use. Simply give the function a few strings, and the user will be able to choose between them.

Spoiler

function menu( ... )
	local tArgs = { ... }
	local maxLen = 0
	for k, v in ipairs( tArgs ) do
		if #v > maxLen then maxLen = #v end
	end
	local maxx, maxy = term.getSize()
	centerx = maxx/2
	centery = (maxy/2) + #tArgs
	local yValue = {}
	term.clear()
	for i = 1, #tArgs do
		term.setCursorPos( centerx - (#tArgs[i]/2), centery - i )
		yValue[ i ] = centery - i
		term.write( tArgs[ i ] )
	end
	local selected = 1
	while true do
		term.setCursorPos( centerx - (maxLen/2) - 2, yValue[ selected ] )
		term.write( "[" )
		term.setCursorPos( centerx + (maxLen/2) + 2, yValue[ selected ] )
		term.write( "]" )
		local event, key = os.pullEvent( "key" )
		local old = selected
		if key == 200 and tArgs[ selected + 1 ] then
			selected = selected + 1
		elseif key == 208 and tArgs[ selected - 1 ] then
			selected = selected - 1
		elseif key == 28 then
			return tArgs[ selected ]
		end
		term.setCursorPos( centerx - (maxLen/2) - 2, yValue[ old ] )
		term.write( " " )
		term.setCursorPos( centerx + (maxLen/2) + 2, yValue[ old ] )
		term.write( " " )
	end
end
Example of use:

local option = menu( "main", "control", "command", "lights" )
if option == "main" then
  --#etc.
elseif option == "control" then
  --#etc.
end
Edited on 17 August 2014 - 11:49 PM