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

Index Expected, Got Nil

Started by whatxDxDxD, 26 September 2013 - 12:29 PM
whatxDxDxD #1
Posted 26 September 2013 - 02:29 PM
Spoiler

list = {}
numbers = {}
deathReasons = {}
screenLoader = {}
  screenLoader["death"] = false
  screenLoader["message"] = false
  screenLoader["login"] = false

--creates table "list" with all infomation (overloaded)
function setTable(...)
  local n = length()+1
  local arguments = {select(1,...)}
  local player = arguments[1]
  if table.getn(arguments) == 1 then
	list[n] = {}
	list[n]["player"] = arguments[1]
	list[n]["deaths"] = 0
	list[n]["kills"] = 0
	list[n]["logins"] = 0
	list[n]["messages"] = 0
	list[n]["average"] = 0
		print("Player " ..player.. " successfully created.")
  elseif table.getn(arguments) == 6 then
	list[n] = {}
	list[n]["player"] = arguments[1]
	list[n]["deaths"] = arguments[2]
	list[n]["kills"] = arguments[3]
	list[n]["logins"] = arguments[4]
	list[n]["messages"] = arguments[5]
	list[n]["average"] = arguments[6]
		print("Player " ..player.. " successfully created.")
  else
	print("Error: setTable: Wrong parameter passed to function 'setTable'!")
  end
end

I'm having trouble with the tables. I wrote the program not directly in computercraft, it workd fine, but now if I try to run the program there's an error-message expected index, got nil referring to the first list[n] (and all the others). The function is just a piece of the program, the setTable function is called with the parameter "dummy". I get the same message no matter what i use as index, tried numbers and strings, the variable n is just the length of the list (had some wierd problems with table.getn(..) that's why I used there the custom function length()).
Somehow every "index" is nil.
Thank you in advance :D/>
makerimages #2
Posted 26 September 2013 - 02:44 PM
Why would yo need the

[n]
behind the list? if it is there, N is used as an index, remove
 [n]
from all list`s and try then

also
#list
returns the lengtht of the list
whatxDxDxD #3
Posted 26 September 2013 - 02:57 PM
Well the [n] makes it easier for me to navigate.
oh, well that's pretty handy, didn't know about that :D/>

hm.. still the same problem if i remove the [n].
Exerro #4
Posted 26 September 2013 - 03:52 PM
Is this your whole code? If it is you should be getting an attempt to call nil error with length( ). Otherwise,make it print n ( or other method that let's you see n ) right after you declare it, I am guessing that there isn't a table list[n] so maybe n isn't what you think it should be.
And as always, whole code really helps us to solve errors. If it is really long put it on pastebin or a in a spoiler.
whatxDxDxD #5
Posted 26 September 2013 - 04:18 PM
tested it, n got the value it should.

pastebin : http://pastebin.com/LcqtDt0B
Spoiler

--Info Board by Southp0le
--adjusted for 6x8 Advanced Monitor
--__work in progress

---------------------
-------Options-------
---------------------

local serverAdmin = "Guracao"
local boardAdmin = "Southp0le"
BackgroundColor = colors.lightBlue
TextColor = colors.black
textSize = 2
os.loadAPI("buttonAPI")
local mon = peripheral.wrap("monitor_1")
local mon2 = peripheral.wrap("top")
local chat = peripheral.wrap("bottom")
local mod = peripheral.wrap("back")
local det = peripheral.wrap("playerDetector_1")
mon.setTextColor(TextColor)
mon.setBackgroundColor(BackgroundColor)
mon.setTextScale(textSize)

-----------------------
-------Functions-------
-----------------------

----------------
--file control--
----------------
--saves the file
function saveFile(filename)
  local file = fs.open(filename,"w")
  if filename == "list" then
	file.write(textutils.serialize(list))
  elseif filename == "numbers" then
	file.write(textutils.serialize(numbers))
  elseif filename == "deathReasons" then
	file.write(textutils.serialize(deathReasons))
  end
  file.close()
  print("File '"..filename.."' saved.")
  refresh()
end

--loads the file and returns the file
function loadFile(filename)
  local file = fs.open(filename,"r")
  local data = file.readAll()
  file.close()
  print("File '"..filename.."' loaded.")
  return textutils.unserialize(data)
end

--checks if theres a file, creates one if not
function checkFile(file)
  if fs.exists(file) == false then
	saveFile(file)
	print("Created a new file: " ..file..".")
  else
	print("Everything fine, file '" ..file.."' exists already.")
  end
end
----------
--Tables--
----------
list = {}
deathReasons = {}
numbers = {}
screenLoader = {}
  screenLoader["death"] = false
  screenLoader["message"] = false
  screenLoader["login"] = false


--creates table "list" with all infomation (overloaded)
function setTable(...)
  local n = lenght()+1
  local arguments = {select(1,...)}
  local player = arguments[1]
  if table.getn(arguments) == 1 then
	list[n] = {}
	list[n]["player"] = arguments[1]
	list[n]["deaths"] = 0
	list[n]["kills"] = 0
	list[n]["logins"] = 0
	list[n]["messages"] = 0
	list[n]["average"] = 0
  elseif table.getn(arguments) == 6 then
	list[n] = {}
	list[n]["player"] = arguments[1]
	list[n]["deaths"] = arguments[2]
	list[n]["kills"] = arguments[3]
	list[n]["logins"] = arguments[4]
	list[n]["messages"] = arguments[5]
	list[n]["average"] = arguments[6]
  else
	print("Error: setTable: Wrong parameter passed to function 'setTable'!")
  end
  print("Player " ..player.. " successfully created.")
end

--returns lenght of list
function lenght()
  local n = 0
	if list ~= nil then
	  for k in pairs(list) do
		n = n +1
	  end
	end
  return n
end

--returns related number from player
function getNumber(player)
  if numbers ~= nil then
	for k in ipairs(numbers) do
	  if numbers[k] == player then
		return k
	  end
	end
  else
	print("Error: getNumber: No players!")
  end
end

--checks if player exists
function checkPlayer(player)
  local x = 0
  if number ~= nil then
	for k in ipairs(numbers) do
	  if numbers[k] == player then
		x=x+1
	  end
	end
  end
  if x > 0 then
	return true
  else
	return false
  end
end

--removes table-entry
function table.removePlayer(player)
  local x = 0
  local key = getNumber(player)
  if checkPlayer(player) then
	table.remove(list, key)
	table.remove(numbers, key)
	table.remove(deathReasons, key)
	saveFile("list")
	saveFile("numbers")
	saveFile("deathReasons")
	print("Player " ..player.. " successfully removed.")
  else
	print("Error: table.removePlayer: Player " ..player.. " could not be removed. Is the name written correctly?")
  end
end

--creates a dummy-player for comparative
--removes it if no longer needed
function dummy()
  local number = lenght()
  --setTable("dummy")
  print("Players:")
  if number == 0 then
	setTable("dummy")
  end
  if list ~= nil then
	for k in ipairs(list) do
	  print(list[k]["player"])
	end
  else
	print(" ")
  end
  if number>1 and checkPlayer("dummy") then
	table.removekey(list,"dummy")
  end
  print("There're " ..number.. " Players on the server.")
end

--adds a new player to the list
function addPlayer()
  while true do
	event,newcomer = os.pullEvent("player")
	local x = 0
	if checkPlayer(newcomer) then
	  chat.tell(newcomer,"Error: "..newcomer..", you're already listed in the database. Don't you remember, Idiot?")
	elseif checkplayer(newcomer) == false then
	  chat.tell(newcomer,"Congratulations! Welcome to this great server, now you're listed in the database. Have fun, "..newcomer..".")
	  setTable(newcomer)
	  saveFile("numbers")
	  saveFile("list")
	else
	  chat.say("Well this shouldn't happen, please report this error to "..serverAdmin.." or " ..infoboardAdmin..".")
	  chat.say("No joke!")
	end
  end
end

--calculates average messagelenght
function average(player, message)
  list[player]["average"] = (tonumber(list[player]["average"]))*(tonumber(list[player]["messages"])-1)
  list[player]["average"] = (tonumber(list[player]["average"]) + string.len(message)) / (tonumber(list[player]["messages"]))
end

function sortByDeathsH(x, y)
  return x.deaths > y.deaths
end

function sortByKillsH(x, y)
  return x.kills > y.kills
end

function sortByLoginsH(x, y)
  return x.logins > y.logins
end

function sortByMessagesH(x, y)
  return x.messages > y.messages
end

function sortByAverageH(x, y)
  return x.average > y.average
end

function sortByDeathsL(x, y)
  return x.deaths < y.deaths
end

function sortByKillsL(x, y)
  return x.kills < y.kills
end

function sortByLoginsL(x, y)
  return x.logins < y.logins
end

function sortByMessagesL(x, y)
  return x.messages < y.messages
end

function sortByAverageL(x, y)
  return x.average < y.average
end

function sortAll (state)
  if screenLoader["death"] then
	if state == "max" then
	  table.sort(list,sortByKillsH)
	elseif state == "min" then
	  table.sort(list,sortByKillsL)
	end
  end
  if screenLoader["message"] then
	if state == "max" then
	  table.sort(list,sortByMessagesH)
	elseif state == "min" then
	  table.sort(list,sortByMessagesL)
	end
  end
  if screenLoader["login"] then
	if state == "max" then
	  table.sort(list,sortByLoginsH)
	elseif state == "min" then
	  table.sort(list,sortByLoginsL)
	end
  end
end

-----------
--Monitor--
-----------

function refresh()
  mon.clear()
  screen()
end

--creates labels
function label(xpos,ypos, text)
  mon.setCursorPos(xpos, ypos)
  mon.write(text)
end

--prints all the labels on the monitor
function printLabel(label1, label2)
  label(2,2,"Player:")
  label(21,2, label1)
  label(33,2, label2)
  label(30,20,"by Southp0le")
end

--prints data on the monitor
--"tostring" to get rid of ".0"
function printData(label1, label2)
  local x=4
  for player in pairs(list) do
	mon.setCursorPos(3,x)
	mon.write(player)
	mon.setCursorPos(25,x)
	mon.write(tostring(list[player][label1]))
	mon.setCursorPos(36,x)
	mon.write(tostring(list[player][label2]))
	x=x+1
  end
end
function toggleScreen(change)
  local boolean = screenLoader[change]
  screenLoader["death"] = false
  screenLoader["message"] = false
  screenLoader["login"] = false
  screenLoader[change] = not boolean
end

function screen()
  if screenLoader["death"] == true then
	printLabel("Kills:", "Deaths:")
	printData("kills", "deaths")
  end
  if screenLoader["message"] == true then
	printLabel("messages:", "average:")
	printData("messages", "average")
  end
  if screenLoader["login"] == true then
	printLabel("kills:", "deaths:")
	printData("kills", "deaths")
  end
end

function fillButton()
buttonAPI.setTable("Kill/Death", toggleScreen("death"),1 , 1, 2,2)
buttonAPI.setTable("Message", toggleScreen("message"),4, 4,5 ,5)
buttonAPI.setTable("Login", toggleScreen("login"), 7,7 , 8,8)
--buttonAPI.setTable("Max", toggleScreen(), , , ,)
--buttonAPI.setTable("Min", toggleScreen(change), , , ,)
end

------------------------
--while true functions--
------------------------
--counts deaths, kills and deathreasons
function deathcount()
  while true do
	event,dead,killer,cause = os.pullEvent("chat_death")
	list[dead]["deaths"] = tonumber(list[dead]["deaths"])+1
	if killer~=nil then
	  for k in pairs(list) do
		if killer == list[k]["player"] then
		  list[killer]["kills"] = tonumber(list[killer]["kills"])+1
		end
	  end
	  local x = 0
	  for i=1, table.getn(deathReasons), 1 do
		for j=1, table.getn(deathReasons[getNumber(dead)]), 1 do
		  if deathReasons[i][j] == killer then
			deathReasons[i][j+1] = deathReasons[i][j] + 1
			x = x+1
		  end
		end
	  end
	  if x == 0 then
		deathReasons[getNumber(dead)][table.getn(deathReasons[getNumber(dead)])+1] = killer
		deathReasons[getNumber(dead)][table.getn(deathReasons[getNumber(dead)])+1] = 1
	  end
	end
	saveFile("deathReasons")
	saveFile("list")
  end
end

--counts numbers of messages
--includes maintenance-options
function messagecount()
  while true do
	event, player, message = os.pullEvent("chat")
	local number = getNumber(player)
	list[number]["messages"] = tonumber(list[number]["messages"])+1
	average(tostring(player),tostring(message))
	saveFile()
	if player == boardAdmin and message == "createPlayer" then
	  chat.tell(boardAdmin,"Waiting for information to create player: Name, Deaths, Kills, Logins, Messages, Average")
	  print("Waiting for information to create player: Name, Deaths, Kills, Logins, Messages, Average")
	  event, player, message = os.pullEvent("chat")
	  if player == boardAdmin then
		local string = message
		local x = 0
		for word in string.gmatch(string, "%w+") do
		  if x == 0 then
			name = word
			print("Player: " ..word)
		  elseif x == 1 then
			kills = word
			print("Kills: " ..word)
		  elseif x == 2 then
			deaths = word
			print("Deaths: " ..word)
		  elseif x == 3 then
			logins = word
			print("Logins: " ..word)
		  elseif x == 4 then
			messages = word
			print("Messages: " ..word)
		  elseif x == 5 then
			average = word
			print("Average Lenght: " ..word)
		  else
		  print("Error: messagecount: createPlayer: String-message not matching")
		  end
		  x=x+1
		end
	  end
	  setTable(name,deaths,kills,logins,messages,average)
	  saveFile("list")
	  saveFile("numbers")
	  saveFile("deathReasons")
	elseif player == boardAdmin and message == "deletePlayer"then
	  chat.tell(boardAdmin,"Waiting for information to delete player: Name")
	  print("Waiting for information to delete player: Name")
	  event, player, message = os.pullEvent("chat")
	  table.removePlayer(tostring(message))
	  saveFile("list")
	  saveFile("numbers")
	  saveFile("deathReasons")
	end
  end
end

--checks for monitortouch
function getClick()
  event,side,x,y = os.pullEvent("monitor_touch")
  button.checkxy(x,y)
end
function printer()
  for k in pairs(list) do
	print(list[k]["player"])
	print(list[k]["deaths"])
	print(list[k]["kills"])
	print(list[k]["logins"])
	print(list[k]["messages"])
  end
end

--function with all pullEvents
function mainProcess()
	parallel.waitForAny(deathcount, messagecount, addPlayer, getClick)
end

-----------
--Process--
-----------
--lifeControl()
checkFile("list")
checkFile("numbers")
checkFile("deathReasons")
list = loadFile("list")
numbers = loadFile("numbers")
deathReasons = loadFile("deathReasons")
dummy()
mainProcess()

So this is the whole code, at the moment a lot of the code is in the testing-state, I'm very sorry, if it is too unorganized, I'm also pretty sure there's stuff that isn't correct or probably not done the best way ( for example the "#list-thing"). :)/> Last time I worked on the code mistyped "legth", but i will replace it anyway..
MR_nesquick #6
Posted 26 September 2013 - 05:37 PM
error code: parallel :22: <name> :443: attempt to index ? (a nil value)

line 443 = < button.checkxy(x,y) >
it should be < buttonAPI.checkxy(x,y) >
whatxDxDxD #7
Posted 26 September 2013 - 05:47 PM
error code: parallel :22: <name> :443: attempt to index ? (a nil value)

line 443 = < button.checkxy(x,y) >
it should be < buttonAPI.checkxy(x,y) >
oh thank you, but why did the program run that far? If I run the program it stops around line 85 I think. So i never got that far ;)/>.
Was there a big change in one of the CC versions? Or what's the difference, did you find the problem with the table?
MR_nesquick #8
Posted 26 September 2013 - 05:51 PM
i'm using FTP direwolf 1,5 v2. and a fresh install of dire button API. i didn't get any error code with your tables. but i get one black screen and one light blue one but nothing is happening
whatxDxDxD #9
Posted 26 September 2013 - 06:15 PM
Ah yes, I didn't adjust all background colors, had different priorities. Oh but that's great to hear :D/>.

Edit:
Did test the program in a new test world, didn't get the table problem. :D/> Seems that my test world was somehow a little broken. Well it wasn't what I expected, but as long as the problem is gone I'm fine. There're still problems with the program, but these seem to be normal programming mistakes. So thank you everybody for this fast help :D/>, I think I would have tested for hours in the old world ^^. great forum :D/>