Having problems with TIC-80 - lua

heyo! i'm trying to do a simple TIC-80 (basically lüa) script, but i'm getting an error.
error started appearing after i added the lastfaced() function. honestly idk what i did wrong.
here's the code:
--width and height vars
w=240
h=136
-- Last faced var
lf='r'
--Player X and Y, W, H, ID vars
p = {
id=0,
x=w/2,
y=h/2,
w=16,
h=16,
draw = function()
spr(p.id, p.x, p.y, 1, 1)
end
}
--movement function here
function lastfaced()
if btn(2) then
lf='l'
elseif btn(3) then
lf='r'
elseif lf="l" then
p.id=4
elseif lf="r" then
p.id=0
end
end
function TIC()
cls(12)
move()
p.draw()
lastfaced()
end
and here's the error:
[string "..."]:49: 'then' expected near '='
can anyone help?

Ehm, when you want to compare you must use == for it to work, one = will not work...
function lastfaced()
if btn(2) then
lf='l'
elseif btn(3) then
lf='r'
elseif lf="l" then
p.id==4
elseif lf=="r" then
p.id=0
end
end

Related

How do I keep the renderBlocks() function from going into an infinite loop?

-- This is Minecraft, but 2D, and in Lua.
-- **************************************
-- ID 0: Air
-- ID 1: Stone
-- ID 2 Logs
-- ID 3: Leaves
-- ID 4: Planks
-- ID 5: Crafting Table
-- ID 6: Furnance
-- ID 7: Player position detector block
-- **************************************
blockTable = { -- Stores all the blocks
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6}
}
tableRow = 1 -- Y value for block render pointer
tableColumn = 1 -- X value for block render pointer
runOnce = true -- Run a loop once
tickNum = 0 -- Number of ticks since startup
function renderBlock(X, Y, K) -- Render a block
if K == 1 then -- if blockID == 1, draw a grey square
screen.setColor(100,100,100)
print(X, Y)
screen.drawRectF(X, Y, 8, 8)
end
if K == 6 then -- If the blockID == draw a grey square
screen.setColor(100,100,100)
screen.drawRectF(X, Y, 8, 8)
end
end
function renderBlocks() -- Render all the blocks (Scans though the blockTable in a raster pattern)
while runOnce == true -- Run this code once
do
while #blockTable >= tableRow
do
while #blockTable[tableRow] >= tableColumn
do
print("TC " .. tableColumn)
tableColumn = tableColumn + 1
blockID = blockTable[tableRow][tableColumn]
renderBlock(tableRow, tableColumn, blockID)
if tableColumn > #blockTable[tableRow] then tableColumn = 1 end
end
runOnce = false
end
print("TR " .. tableRow)
tableRow = tableRow + 1
end
end
function onTick()
print("Tick! Tick count: " .. tickNum) -- Print the current tick, as well as say that there has been a tick
tickNum = tickNum + 1
end
function onDraw()
while runOnce == true -- Run this code once
do
renderBlocks()
runOnce = false
end
end
Here's my code in the IDE for the framework: Link
I have no clue why this is happening, I'm at a loss here.
When doing loops over tables it is far better to use for loops than while or repeat loops, that are far more difficult to understand and bugfix.
Use for index,value in ipairs(yourtable) do if you want to get the indices (number in the table) and the values associated or for key,value in pairs(yourtable) do if you want to get the keys (generally strings that is used as key for a value: yourTable["key"] = 0) and the values associated with it.
for row,innerTable in ipairs(blockTable) do
for col,value in ipairs(innerTable) do
print("TC " .. col)
blockID = value
renderBlock(row, col, blockID)
end
end
The last should do it inside your renderBlocks function. But that:
while runOnce == true do
-- Doing something
runOnce = false
end
Is not very nice stuff. If it shall only be called once, do not put it into a loop!
Also it would help to have a little better code identation to understand what is happening faster. And add some Space between blocks of code that handle different concerns.
Edit: So your function could look like this:
function renderBlocks()
if runOnce then
runOnce = false
for row,innerTable in ipairs(blockTable) do
for col,value in ipairs(innerTable) do
blockID = value
renderBlock(row, col, blockID)
end
end
end
end
There are a couple issues in your renderBlocks() function
function renderBlocks()
while runOnce == true do
while #blockTable >= tableRow do
while #blockTable[tableRow] >= tableColumn do
print("TC " .. tableColumn)
tableColumn = tableColumn + 1
blockID = blockTable[tableRow][tableColumn]
renderBlock(tableRow, tableColumn, blockID)
if tableColumn > #blockTable[tableRow] then
tableColumn = 1
end
end
runOnce = false
end
print("TR " .. tableRow)
tableRow = tableRow + 1
end
end
First we can look at the inner most loop. Here we have a problem with the contrition used to evaluate the loop and how it is incremented.
while #blockTable[tableRow] >= tableColumn do
print("TC " .. tableColumn)
tableColumn = tableColumn + 1 -- incremented here
blockID = blockTable[tableRow][tableColumn]
renderBlock(tableRow, tableColumn, blockID)
if tableColumn > #blockTable[tableRow] then
tableColumn = 1 -- reset here
end
end
in the loop body you do tableColumn = tableColumn + 1 and later in the same body you do if tableColumn > #blockTable[tableRow] then tableColumn = 1 end so this is a problem when tableColumn is increased to a value that would end the loop we reset it to 1 preventing the loop from ever ending.
Now lets look at the next loop up. Here we never increment tableRow it is incremented just after the end of this loop so it is not possible for the loop to end.
while #blockTable >= tableRow do
while #blockTable[tableRow] >= tableColumn do
...
end
runOnce = false
end
I believe you intended
print("TR " .. tableRow)
tableRow = tableRow + 1
to occur within this loop not outside of it.
You're missing a few block definitions here. Don't think that's what's sending it into an infinite loop, but you might not see results, otherwise.
function renderBlock(X, Y, blockID) -- Render a block
if blockID == 0 then -- Air
-- screen.setColor(10, 20, 220, 0) -- is there an alpha channel?
screen.setColor(10, 20, 220)
elseif blockID == 1 then -- Stone
screen.setColor(100, 100, 100)
elseif blockID == 2 then -- Logs
screen.setColor(200, 50, 50)
elseif blockID == 3 then -- Leaves
screen.setColor(20, 220, 40)
elseif blockID == 4 then -- Planks
screen.setColor(180, 30, 10)
elseif blockID == 5 then -- Craft Table
screen.setColor(180, 30, 10)
elseif blockID == 6 then -- Furnace
screen.setColor(100, 100, 100)
elseif blockID == 7 then -- Player detect
screen.setColor(220, 30, 30)
end
print(X, Y)
screen.drawRectF(X, Y, 8, 8)
end
It's easy to use for loops. set initial condition, then the final, completed condition, and let it run the course.
function renderBlocks() -- Render all blocks (Scans though blockTable in a raster pattern)
for row = 1, #blockTable do
for col = 1, #blockTable[row] do
print("TC " ..col)
local blockID = blockTable[row][col]
renderBlock(row, col, blockID)
end
print("TR " ..row)
end
end
You likely don't need that runOnce. If you find you do for something else, go ahead, but it shouldn't be needed with a nested for loop.
function onDraw()
renderBlocks()
end

lua attempt to call method 'len' (a nil value)

in my lua project I got the following function:
function module.Cp1251ToUtf8(s)
if s == nil then return nil end
local r, b = ''
for i = 1, s and s:len() or 0 do --the problem occurs here
b = s:byte(i)
if b < 128 then
r = r..string.char(b)
else
if b > 239 then
r = r..'\209'..string.char(b - 112)
elseif b > 191 then
r = r..'\208'..string.char(b - 48)
elseif cp1251_decode[b] then
r = r..cp1251_decode[b]
else
r = r..'_'
end
end
end
return r
end
So as far as I understand this function gets a string and converts its encoding. Sometimes it works fine, but sometimes I get the following error: attempt to call method 'len' (a nil value). Any ideas what would it be and how to fix it?
I tried to remove s:len() or insert a condition like if s != nil then ... but it also did not work.
if s == nil then return nil end
The above rejects nil-values. But there are other non-strings, so tighten your check:
if type(s) ~= 'string' return nil end

Lua <eof> expected near 'print'

I'm having trouble with in lua.
Problem one:
Every time I run the following program the console tells me:
'end' expected (to close 'function' at line 1) near 'local'
Please notice where I've marked in all caps comments details about the error
function m11()
local inst = mc.mcGetInstance() -- controller instance
local gcodeLineNbr = mc.mcCntlGetGcodeLineNbr(inst) -- get current Gcode line number
local gcodeLineStr = mc.mcCntlGetGcodeLine(inst, gcodeLineNbr) -- get current Gcode line
function valFromLine(string, axis)
local startPoint = string.find(string, axis) + 1
local outputVal = ""
local isNum = true
while isNum do
local num = string.sub(string, startPoint, startPoint)
startPoint = startPoint + 1
if num ~= " " then
outputVal = outputVal .. num
else
isNum = false
end
end
outputVal = tonumber(outputVal)
end
return outputVal
--COMPILER HIGHLIGHTS FOLLOWING LINE AS LOCATION OF ERROR
local gcodeLocX = valFromLine(gcodeLineStr, "X")
local curLocX = mc.mcAxisGetPos(inst, 0) -- get current X axis value
local curLocY = mc.mcAxisGetPos(inst, 1) -- get current Y axis value
local curLocZ = mc.mcAxisGetPos(inst, 2) -- get current Z axis value
local curAngB = mc.mcAxisGetPos(inst, 4) -- get current C axis value
local curAngC = mc.mcAxisGetPos(inst, 5) -- get current C axis value
local toolOffset = mc.mcCntlGetToolOffset(inst, 2) -- get tool offset for axis Z
function rotateToolB()
local comHypot = toolOffset * math.sin(angle) -- get XY planar dist from C pivot to tool centre point
local compDestinX = comHypot * math.sin(math.rad(90) - curAxisC + curLocX
end
end
--END OF M11() FUNCTION SHOULD BE HERE
if (mc.mcInEditor() == 1) then
m11()
end
I can't see why it's expecting m11() to close so early.
Problem two:
I rewrote valFromLine() in a completely separate file and I get:
'eof' expected near 'print'
function valFromLine(string, axis)
local startPoint = string.find(string, axis) + 1
local outputVal = ""
local isNum = true
while isNum do
local num = string.sub(string, startPoint, startPoint)
startPoint = startPoint + 1
if num ~= " " then
outputVal = outputVal .. num
else
isNum = false
end
end
outputVal = tonumber(outputVal)
end
return outputVal
print(valFromLine("GO1 X254.348 Y1039.456 Z150.13 B90.23 C13 M11", "X"))
I've counted my 'end' statements, I can't find what's wrong with them in either examples of code. I'm at a complete loss for ideas at this point, please help. Thanks.
The line return outputVal is at the wrong position. Move it into the function valFromLine.
You cannot return outside the function.
correct:
function someFunction()
-- do something
local something = "something"
return something
end
wrong:
function someFunction()
-- do something
local something = "something"
end
return something
Defining global functions withn a function is also not very clean, use locals.

"quit" read as nil field?

I am making a menu file for my game, and it's can't call "quit" as a field. It always returns nil. Can anyone tell me why this is happening? Note, it is declared earlier in the code and the other button function does work. Thanks!
function love.mousepressed( x, y, button )
if button == "l" then
for k, v in pairs(buttons) do
local ins = insideBox( x, y, v.x - (v.w/2), v.y - (v.h/2), v.w, v.h)
if ins then
if v.action == "play" then
loadState("game")
end
end
if ins then
if v.action == "quit" then
love.event.quit()
end
end
end
end
end
Why would you have play and quit bound to the same button? o.O
Also, there's no need to check ins twice. Duplicate code should be a red flag:
if ins then
if v.action == "play" then
loadState("game")
end
end
if ins then
if v.action == "quit" then
love.event.quit()
end
end
That could be:
if ins then
if v.action == "play" then
loadState("game")
elseif v.action == "quit" then
love.event.quit()
end
end
But short of using a debugger, here's how you track down such problems:
1. Create a file called conf.lua in your project folder.
2. Have at least this much inside it, to attach a console to your app:
function love.conf(t)
t.console = true -- Attach a console (Windows only)
end
3. Add debugging output to your mousepressed function so you can see what's going on.
First define this somewhere early in your app execution. Handy printing function:
function printf(...) print(string.format(...)) end
Then add some debugging stuff to your function:
function love.mousepressed(x, y, button)
print('mouse button %d pressed at %d, %d', button, x, y)
if button == "l" then
printf('checking %d buttons', #buttons)
for k, v in pairs(buttons) do
local ins = insideBox( x, y, v.x - (v.w/2), v.y - (v.h/2), v.w, v.h)
printf('%d, %d is%sinside button %s (%d, %d, %d, %d)',
ins and ' ' or ' not ', k, x, y, v.x, v.y, v.w, v.h)
if ins then
print('executing action', v.action)
if v.action == "play" then
loadState("game")
elseif v.action == "quit" then
love.event.quit()
end
end
end
end
end
You should also used meaningful variables names. v can be button. What is k? An index? Then perhaps i or index. Is it a name? Then name. So on and so forth. k tells us nothing.

Expected table. got nil error?

In the following code
for k, smoke in pairs(self.smokes) do
smoke.time = smoke.time - dt
if smoke.time <= 0 then
table.remove( self.smokes, k )
end
end
It's telling me that self.smokes is a nil value, although later in the code I declare
function ent:Smoke()
table.insert( self.smokes, {time = 3, x = self.x, y = self.y} )
end
Anyone know my error? Thanks guys!
Because the function ent:Smoke is run later in the code.
Place it up at the top and it will work.
Perhaps you want this:
function ent:Smoke()
self.smokes = {time = 3, x = self.x, y = self.y}
end
And you would need to change the other code too:
if self.smokes then
self.smokes.time = self.smokes.time - dt
if self.smoke.time <= 0 then
self.smokes = nil
end
end
The function table.insert() is for inserting into array type tables.

Resources