Why do I use 'end)' instead of just end |? - lua

draw.RoundedBox(0,0,0,100,100,Color(120,255,120))
end)
I'm watching tutorials for learning Lua, more specifically Lua for the Garry's Mod engine. During the tutorial, I noticed using just 'end' didn't work. I had to use 'end)' with a ')'.
Why do I have to place a ')' at the end of end in this code?

Some functions take other functions as parameters.
When you see a function called like this:
hello(param, function(a) print(a) end)
(Sorry, poor example. This function doesn't really do anything) The function on the inside is called internally from the source of the hello function.
The end is the end of the inside function, and the ) is the end of the parameter list for the first function.
So here we have a function hook.Add() being called:
hook.Add("HUDPaint", "DrawMyHud", function()
draw.RoundedBox(0,0,0,100,100,Color(120,255,120))
end)
and from the GMOD wiki:
hook.Add( string eventName, any identifier, function func )
--Add a hook to be called upon the given event occurring.
Although we're calling a function, what the function is doing is creating a special connection in the code called a hook. On the event "HUDPaint", the GMOD client will call the function provided.
Another way to write this function that might make the meaning of end) more clear is by making each parameter it's own line:
hook.Add(
"HUDPaint",
"DrawMyHud",
function() draw.RoundedBox(0,0,0,100,100,Color(120,255,120)) end --end of function declaration
) --end of hook.Add function call

Related

PANIC: unprotected error in call to Lua API (init.lua:116: attempt to call field 'alarm' (a nil value))

I keep getting an error on this line of code, how can I solve this? Thanks in advance
tmr.alarm(0, 250, tmr.ALARM_AUTO, function()
You are obviously using an outdated example snippet from somewhere. There is no tmr.alarm function in the timer module.
See https://nodemcu.readthedocs.io/en/latest/modules/tmr/ for the current API documentation. There is a alarm() function on a timer object i.e. you first need to create a timer object. The below example is straight from the documentation:
if not tmr.create():alarm(5000, tmr.ALARM_SINGLE, function()
print("hey there")
end)
then
print("whoopsie")
end

lua: init.lua:15: attempt to call method 'alarm' (a nil value)

i am trying to fix a piece of code i did find online. (yeah i know....)
But in case you guys can help me out wihth this error it would be just amazing:
Error: lua: init.lua:15: attempt to call method 'alarm' (a nil value)
Code (from here: https://github.com/Christoph-D/esp8266-wakelight)
dofile("globals.lc")
wifi.setmode(wifi.STATION)
wifi.sta.config(WIFI_SSID, WIFI_PASSWORD)
wifi.sta.sethostname(MY_HOSTNAME)
if WIFI_STATIC_IP then
wifi.sta.setip({ip = WIFI_STATIC_IP, netmask = WIFI_NETMASK, gateway = WIFI_GATEWAY})
end
wifi.sta.connect()
-- Initialize the LED_PIN to the reset state.
gpio.mode(LED_PIN, gpio.OUTPUT)
gpio.write(LED_PIN, gpio.LOW)
tmr.alarm(
MAIN_TIMER_ID, 2000, tmr.ALARM_AUTO, function ()
if wifi.sta.getip() then
tmr.unregister(MAIN_TIMER_ID)
print("Config done, IP is " .. wifi.sta.getip())
dofile("ledserver.lc")
end
end)
What can i do there? Whats wrong?
Cheers and thank you!!!
It is all in the manual. You just have to read it.
There is an example of how to use the alarm method of timer objects.
if not tmr.create():alarm(5000, tmr.ALARM_SINGLE, function()
print("hey there")
end)
then
print("whoopsie")
end
You attempted to call tmr.alarm but it is tobj:alarm. The manual does not mention tmr.alarm. This function was removed from NodeMCU in January 2019.
You're using code you found online that is basedn on an older NodeMCU version. It is using functions that are deprecated by now.
See https://github.com/nodemcu/nodemcu-firmware/pull/2603#issuecomment-453235401
and
https://github.com/nodemcu/nodemcu-firmware/compare/5b22e1f9aee77095ab99dd6240ebd9dddd1cc5a0..c6444ecb6088d20e95197d808d8303c8093faab5
So you have to create a timer object first befvor you can use any of its methods. alarm is not a method of the tmr module anymore.
Edit
First you have to create a timer object https://nodemcu.readthedocs.io/en/latest/modules/tmr/#tobjcreate
local tObj = tmr.create()
Then you have to register a callback and start the timer. There is a convenience function alarm that does both for us.
And when we do not need our timer anymore we have to free the resources by calling
tObj:unregister()
Try something like
-- create a timer object
local tObj = tmr.create()
-- register an alarm
tObj:alarm(2000, tmr.ALARM_AUTO, function ()
if wifi.sta.getip() then
tObj:unregister()
print("Config done, IP is " .. wifi.sta.getip())
dofile("ledserver.lc")
end
end)

Pico-8 coroutines are occasionally dead

I was trying to replace a for-loop with coroutines to move the stars:
--fine
function _update()
for c in all(boids) do
move_boid(c)
end
end
--broken
function _update()
for c in all(boids) do
coresume(cocreate(move_boid),c)
end
end
Notice that a fixed number of stars are frozen (I'm pretty sure the number is fixed):
But why? How can I handle this? The complete code is on itch.
Thanks for #Vald and #Egor's comments. Seems the problem is caused by "too-long coroutines" to finish in a PICO-8 cycle. So the solution is that I store unfinished coroutines in a table and resume them if not finished. But somehow the movement is changed, kinda like "lost frame".
Here's my edited code:
function _init()
-- code
cors={}
end
function _update()
for i=1,#boids do
local co=cocreate(move_boid)
local c=boids[i]
add(cors,co)
coresume(co,c)
end
for co in all(cors) do
if (co and costatus(co)!="dead") then
coresume(co)
else
del(cors,co)
end
end
end
And also modify the calculation function, adding a new line in the middle:
function move_boid(c)
-- code
yield()
-- code
end
Just to yield before it's completed.
Update: another way to do it is reusing coroutines.
function _init()
-- code
-- create coroutines
cors={}
for i=1,#boids do
local co=cocreate(move_boid)
local c=boids[i]
add(cors,co)
coresume(co,c)
end
end
function _update()
foreach(cors,coresume)
end
-- and wrap the move function with a loop
function move_boid(c)
while true do
-- code
yield()
-- code
yield()
end
end

Difference between "end" and "end)"?

A while ago I had stumbled upon script tutorials where end was used. But then, a few pages later, I've found an end) instead of just end. So I was troubled by this, what is the closing bracket meant to do?
There is no end) syntax. There is end and ), both with their own meanings. end closes a block (initiated with if, for, do, while or function) and ) closes something that started with (, an expression in parentheses, parameter list etc. You have to use end where a block was started, and use ) where something was started with (.
Since the only way a block can appear in an expression is via a function, both those parts of syntax can appear together, if a function is a part of a complex expression or an argument list. However, it's nothing special really, something like end} or end] can appear the same way.
local func = function() print("hello") end
string.dump(func)
This is the same as:
string.dump(function() print("hello") end)
end is a part of the function syntax (function expression), and ) is a part of the ( syntax (function call here).
The first line in the first piece of code can be also written like this:
local func = (function() print("hello") end)
Here, ) just closes the first parenthesis, and the expression is identical to the original one.
I assume you're talking about ROBLOX's modded version of Lua, if so then
end) would end :connect, for example.
workspace.part.Touched:connect(function(part)
--stuff
end)
If not then refer to llidanS4's answer.

World of Warcraft Lua - If statement flow

I'm trying to create an addon for World of Warcraft. I have created a function that checks whether a buff has been added to the current player.
Button:RegisterEvent("UNIT_AURA");
local function auraGained(self, event, ...)
if (UnitAura("player", "Heating Up")) then
if (heatingUpIsActive ~= 1) then
heatingUpIsActive = heatingUpIsActive + 1
print (heatingUpIsActive)
end
end
Button:SetScript("OnEvent", auraGained);
This works great, but how do I check if UnitAura is not "Heating Up"?
Also, I would prefer if heatingUpIsActive were a boolean, but it seems to not like when I do that. What is the correct way to create a boolean in Lua?
Your function isn't checking the aura that caused the event. It's looking for "Heating Up" any time any UNIT_AURA event comes by. In fact, it looks like the UNIT_AURA event doesn't actually tell you which aura triggered it. So you can't "check if UnitAura is not "Heating Up"", because you simply don't know what aura caused the event. Perhaps it was even several auras at once.
However, the event does tell you what unit got the aura. It's the first vararg. You should probably check to make sure it's player before doing something
local unitid = ...
if unitid ~= "player" then return end
Also, you didn't explain what problems you had with booleans. You should just be able to say something like
if not heatingUpIsActive then
heatingUpIsActive = true
-- do whatever you want
end
although I never saw any declaration of the variable in your code. It's a bad idea to use globals for things like this, so you should declare
local heatingUpIsActive
before the function declaration, e.g.
local heatingUpIsActive
local function auraGained(self, event, ...)
-- ...

Resources