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

[LUA] Unfamiliar with LUA, Attempt to Index Nil (see last post)

Started by Astral, 01 March 2013 - 06:24 PM
Astral #1
Posted 01 March 2013 - 07:24 PM
So I've never really played with LUA before, but I've coded in C and C++ and am somewhat familiar with similar languages. However, when I run the program I've created, it doesn't change outputs to the monitors (to On, or Off), and doesn't actually create output to the bundled cables nor print the toggle in the main screen.

Any ideas? I'm working out different thoughts as I edit this post multiple times.

Program in full (named power)

local function runPower (tempTable)
  do
  local z = 1 --Default monitor position
  local stringTable = {"Quarry Pow: ", "General Pow: ", "Hellfire Gen: ", "Recycler: ",  "Biomass Prod: ", "Biofuel Prod: ", "Refinery: ", "Fuel Power: ", "Biofuel Gen: "}
  mon = peripheral.wrap("left")
  mon.clear()
	for z=1,9 do
	  mon.setCursorPos(1,z)
	  mon.write(stringTable[z])
	  mon.write(tempTable[z])
	end
  end
end

do
--Initialization
  --In order, Quarry, General Power, Lava Power, Recycler, Biomass production, Biofuel Production, Refinery, Combustion Engines, Biofuel Power,
  local toggleTable = {"Off", "Off", "Off", "Off", "Off", "Off", "Off", "Off", "Off"}
  local outputTable = {1, 2, 4, 2048, 32768, 16, 16384, 512, 32}
  local textTable = {"Quarry set to ", "General power set to ", "Recycler power set to ", "Biofuel power set to ", "Biofuel production set to ", "Hellfire power set to ", "Biomass production set to ", "Refinery set to ", "Combustion engines set to "}
  local exitvar  = false --Set to 1 to exit loop
  local outputs  = 0 --Default output cable status all off
  local command  = 100 --Allows selections
  redstone.setBundledOutput("back", outputs)  --Init outputs to 0
  print(command)
  print(quarrypw)
end

do
  term.clear()
  textutils.slowPrint("Power v0.2")
  print("Hit Enter to continue")
  io.read()
end

while true do
	if exitvar == true then break end --- Exit loop if exitvar set to true
	print("Enter command to toggle:")
	print("0 = Exit")
	print("1 = Quarry Power")
	print("2 = General Power")
	print("3 = Recycler Power")
	print("4 = Biofuel Power")
	print("5 = Biofuel Production")
	print("6 = Lava Power")
	   print("7 = Biomass Production")
	   print("8 = Fuel Refinery")
	   print("9 = Combustion Power")
	command = tonumber(read())
	--debug
	
	  if command == 0 then
		exitvar = true
		end
	  if command > 0 then
   	 if boolTable[command] == "On" then
   	   boolTable[command] = "Off"
		  write(textTable[command])
		  write(toggleTable[command])
		  outputs = outputs - outputTable[command]
	  end
   	 if boolTable[command]=="Off" then
		  boolTable[command] = "On"
		  write(textTable[command])
		  write(toggleTable[command])
		  outputs = outputs + outputTable[command]
	  end
		 redstone.setBundledOutput("back", outputs)
		 runPower(boolTable) --Set outputs to cable and run monitor output
	  end	
end	

do
  term.clear()
  print("Exiting... press any key to continue")
  io.read()
  term.clear()
end

Lyqyd #2
Posted 01 March 2013 - 08:32 PM
Split into new topic.

You're passing runPower a series of 1s and 0s, then comparing those against 4, 2048 etc., which obviously doesn't work. Also, tables! This code could be significantly shorter with use of tables. :)/>
Astral #3
Posted 01 March 2013 - 09:52 PM
I had thought that my original code with runPower wasn't producing results, for some reason. Any good tutorials on tables as they would be used in this fashion? I was thinking the "for each 1-9, do x", but it helps me to think out my code by simplifying it to start.

It almost feels like the if/then statements within the body aren't doing anything past setting the toggle variable (quarry, genpower, etc), as it doesn't print the "X set to On" statement either, and attempting to use the exit variable (0) doesn't actually exit from the loop.

Posted edited code in original post.
Lyqyd #4
Posted 02 March 2013 - 04:27 AM
Well, those if statements won't work either. The read() (and by extension io.read()) function returns a string, so comparison against a number would of course fail. You can either use `command = tonumber(read())` or put your comparison numbers in quotes so that they are also strings.
Astral #5
Posted 02 March 2013 - 08:27 AM
That's good to know, thought that if it didn't use quotes it would end up using an int as a default instead.

Edit: Fixed last problem, now when attempting to call a command in the program I receive power:56 attempt to index ? (a nil value) Will update code in main post in a second.

Line 56

   	 if toggleTable[com] == "On" then


It doesn't seem to like using the call for the command variable in trying to figure out which table value to write back. Any ideas on this one? I've created a test program that doesn't appear to give the same error while usin the same commands, and can't seem to figure out why this one isn't working.
Astral #6
Posted 02 March 2013 - 03:22 PM
I finally figured it out… in a way.

Rewrote the code from scratch and cleared up some logic that didn't make sense while doing so. Sometimes it helps to not get stuck in the same patterns of thinking when doing these things.If I had the time or resources when setting this up originally, I would have probably used powers of two for the cable output, something for a future project maybe, as well as allowing the current on/off variables to be stored to/read from files.

If you'd like, you can close this particular thread.

Final code (as of now):

local function runOutput(tempTable)
	do
	local i = 1
	local outputTable = {"Quarry Pow: ", "General Pow: ", "Hellfire Gen: ", "Recycler: ",  "Biomass Prod: ", "Biofuel Prod: ", "Refinery: ", "Fuel Power: ", "Biofuel Gen: "}
	mon = peripheral.wrap("left")
	mon.clear()
	for i=1,#tempTable do
		mon.setCursorPos(1,i)
		mon.write(outputTable[i])
		mon.write(tempTable[i])
	end
	end
end

do
	--initialize
	local toggleTable = {"Off","Off","Off","Off","Off","Off","Off","Off","Off"}
	local cableTable = {1, 2, 4, 2048, 32768, 16, 16384, 512, 32}
	local textTable = {"Quarry set to ", "General power set to ", "Recycler power set to ", "Biofuel power set to ", "Biofuel production set to ", "Hellfire power set to ", "Biomass production set to ", "Refinery set to ", "Combustion engines set to "}
	local exitvar = 0
	local outputs = 0
	local com = 0
	redstone.setBundledOutput("back",outputs)
	term.clear()
	textutils.slowPrint("Power v1.0")
	
	while exitvar==0 do
		print("Enter command to toggle:")
		print("0 = Exit")
		print("1 = Quarry Power")
		print("2 = General Power")
		print("3 = Recycler Power")
		print("4 = Biofuel Power")
		print("5 = Biofuel Production")
		print("6 = Lava Power")
		print("7 = Biomass Production")
		print("8 = Fuel Refinery")
		print("9 = Combustion Power")
		
		com=tonumber(read())
		if com == 0 then
			exitvar = 1
		else
		if toggleTable[com]=="On" then
			toggleTable[com] = "Off"
			write(textTable[com])
			write(toggleTable[com])
			outputs = outputs - cableTable[com]
   	 else
			toggleTable[com] = "On"
			write(textTable[com])
			write(toggleTable[com])
			outputs = outputs + cableTable[com]
		end
		redstone.setBundledOutput("back", outputs)
		runOutput(toggleTable)
		end
	end
	term.clear()
	print("Exiting... press any key to continue")
	io.read()
	term.clear()
end
Lyqyd #7
Posted 02 March 2013 - 05:05 PM
There we go, that looks a little better. You can also do stuff like this:


tableOfData = {
  {
    name = "Generator"
    state = false
    output = colors.blue
  },
  {
    name = "Refinery"
    state = true
    output = colors.red
  }
}

print(tableOfData[1].name) --outputs "Generator"

This would let you use one table which has entries containing the sets of data. This reduces the chances of human error when adding or removing entries.