Disclaimer I dont know how to code at all and this is my first atempt at rewriting someone elses addon.
I need to check for the following before the addon loads at all.
frame:RegisterEvent("CLUB_STREAM_SUBSCRIBED");
The issue is, I dont know where or how to do that. I tried adding it on line 19 and then changing line 6 to if event == 'ADDON_LOADED' and arg1 == 'unitscan' and event == 'CLUB_STREAM_SUBSCRIBED' then
The entire code can be found at https://github.com/Damnedprinter/unitscan/blob/master/unitscan.lua
Bottom line up front:
You have, at a minimum, a mistake in Boolean logic where you say
event == 'this' and event == 'that'
but obviously something cannot be both at the same time. You can remedy this using two methods:
if ... elseif ... end (recommended for most situations)
event == 'this' or event == 'that' (not recommended)
Detailed Answer:
1. How the original addon works:
Your code on GitHub is comparable to the following:
local frame = CreateFrame("Frame");
frame:SetScript("OnEvent", function(__, event, arg1)
if (event == "ADDON_LOADED" and arg1 == "unitscan") then
doStuff();
end
end);
frame:RegisterEvent("ADDON_LOADED");
This creates a frame and tells it to respond whenever any addon finishes loading. It responds with an event handler that receives the type of the event (as event) and an argument (as arg1) which can mean different things for different kinds of events. In this example, arg1 will be the name of the addon that just finished loading (see ADDON_LOADED on Wowpedia).
The original author didn't want to do something when just any addon is loaded, so it checks to see that arg1 equals "unitscan" during the ADDON_LOADED event.
RegisterEvent is what causes the handler to be active. I can see in your source code on Git that there are in fact three different events which share the same handler... so that's why it always checks if event == 'NAME_OF_EVENT' to disambiguate which one is happening.
2. Making it work for you:
If you want the addon to also respond to CLUB_STREAM_SUBSCRIBED then I recommend using another elseif statement like in this example:
frame:SetScript("OnEvent", function(__, event, arg1, arg2)
if (event == "ADDON_LOADED" and arg1 == "unitscan") then
doStuff();
elseif (event == "CLUB_STREAM_SUBSCRIBED") then
doOtherStuff();
end
end);
Note I changed the handler to receive two arguments that I arbitrarily called arg1 and arg2. According to documentation on Wowpedia, these will be the club and stream IDs respectively. I don't know if you need these ID values for your purposes, but offer it just in case.
3. An alternative solution:
I don't recommend this solution for you! This is just an alternative.
If you want to execute the exact same code for both events, then you could simplify the above by using an or operator and some parenthesis to control the order of operations.
frame:SetScript("OnEvent", function(__, event, arg1, arg2)
if (
(event == "ADDON_LOADED" and arg1 == "unitscan")
or (event == "CLUB_STREAM_SUBSCRIBED")
) then
doStuff();
end
end);
4. Yet another solution, responding to the comment below rather than the original question
If the goal is to delay execution, then you might consider changing from ADDON_LOADED to another event such as PLAYER_ENTERING_WORLD. However, this also fires when you are entering an instance or travelling on the boat to another continent. As such, the sample code below deregisters the event to prevent this frame from acting on it more than once.
frame:SetScript("OnEvent", function(__, event, ...)
if (event == "PLAYER_ENTERING_WORLD") then
frame:UnregisterEvent("PLAYER_ENTERING_WORLD");
doStuff();
end
end);
frame:RegisterEvent("PLAYER_ENTERING_WORLD");
Related
I would like to use the SetMKeyState(...) and GetMKeyState(...) functions available in the Logitech LUA scripting api, to write some macros.
I am using Windows 10 and the latest version of Logitech GHUB (I can't use LGS for various reasons). On my keyboard, Logitech G815, it seems that any call to SetMKeyState(...) from a LUA macro does not do anything. While the GetMKeyState(...) seems to correctly return the current MKey state. I have read the docs related to these two functions in the "G-series Lua API V8.45" documentation and it looks like I am using them correctly.
For example, the following LUA script should switch the MKey state between M1/M2/M3 using the G1 key, but actually does not do anything (although the code is executed, as the debug log lines appear):
function OnEvent(event, arg)
if (event == "G_PRESSED" and arg == 1) then
currentState = GetMKeyState("kb")
OutputLogMessage("Current MKey state: %d\n", currentState)
newState = currentState + 1
if newState == 4 then
newState = 1
end
OutputLogMessage("Setting new MKey state: %d\n", newState )
SetMKeyState(newState , "kb");
end
end
Am I doing anything wrong here ?
If it is expected that the SetMKeyState(...) function is not supported on the Logitech G815, then which keyboard model would correctly support the SetMKeyState(...) function to change the MKey state ?
It's not actually an answer, just a suggestion, but IDK the way to paste the code in comments, so hope you will forgive me :)
There is a reference code in API doc:
-- Set the current M Key state to M1 when G1 is pressed
function OnEvent(event, arg)
if (event == "G_PRESSED" and arg == 1) then
SetMkeyState(1);
end
end
If I were you I'd get started from the check if it works or not as it is, without any change.
Then, step by step:
add debug messages;
recheck;
try to set it to 2 instead of 1;
try to set it to 3;
try to read and print current state, before and after the operation, considering this remark from API doc: "Calling GetMKeyState immediately afterwards, will likely return the previous state. Use the OnEvent handler to determine when the operation has completed."
I'm trying to implement a script that catches when my character casts a certain spell like for example a Chaos Bolt which has casting time or a Shadow Word: Pain (instant cast). Searching i found the "channeling" events, but i don't quite understand yet.
I'm expecting to trigger a custom message or play an audio when the character casts a certain spell.
UNIT_SPELLCAST_SENT: "unit", "target", "castGUID", spellID"
UNIT_SPELLCAST_SUCCEEDED: "target", "castGUID", spellID
Every spellcast has a unique castGUID. It is created when you begin casting with UNIT_SPELLCAST_SENT, and it appears at the end of cast/channel or instantly in the UNIT_SPELLCAST_SUCCEEDED.
So whenever unit == "player", just record the castGUID and then look for spells completing with that same value. This is how you know it was not someone else's spell.
Meanwhile, you can lookup the spellID corresponding to every spell. In the example below, I used the two from your post (196670 and 589).
local myFrame = CreateFrame("Frame");
local myCurrentCast;
myFrame:RegisterEvent("UNIT_SPELLCAST_SENT");
myFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED");
myFrame:SetScript("OnEvent",
function(self, event, arg1, arg2, arg3, arg4)
if (event == "UNIT_SPELLCAST_SENT" and arg1 == "player") then
print("I am casting something");
myCurrentCast = arg3;
elseif (event == "UNIT_SPELLCAST_SUCCEEDED" and arg2 == myCurrentCast) then
if (arg3 == 196670) then
print("I just finished casting Chaos Bolt!");
elseif (arg3 == 589) then
print("Look at my instant Shadow Word: Pain. Isn't it cool?");
end
end
end
);
This example creates a frame, registers the two events, and then creates an event handler to print out fancy text when you cast the two sample spells. For a tutorial on event handlers, I recommend Wowpedia/Handling_events.
I'm trying to create a while true do loop, that reacts to clicks, using os.pullEvent, and also updates a monitor.
Problem being, it only updates the screen when I press one of the on screen buttons, and I've found out that's because pullEvent stops the script, until an event is fired.
Is it possible to make it so pullEvent doesn't stop me updating the monitor?
function getClick()
event,side,x,y = os.pullEvent("monitor_touch")
button.checkxy(x,y)
end
local tmp = 0;
while true do
button.label(2, 2, "Test "..tmp)
button.screen()
tmp++
getClick()
end
You can easily use the parallel api to run both codes essentially at the same time. How it works is it runs them in sequence until it hits something that uses os.pullEvent and then swaps over and does the other side, and if both stop at something that does os.pullEvent then it keeps swapping between until one yields and continues from there.
local function getClick()
local event,side,x,y = os.pullEvent("monitor_touch")
buttoncheckxy(x,y)
end
local tmp = 0
local function makeButtons()
while true do
button.label(2,2,"Test "..tmp)
button.screen()
tmp++
sleep(0)
end
end
parallel.waitForAny(getClick,makeButtons)
Now if you notice, first thing, I've made your while loop into a function and added a sleep inside it, so that it yields and allows the program to swap. At the end you see parallel.waitForAny() which runs the two functions that are specified and when one of them finishes, which in this case whenever you click on a button, then it ends. Notice however inside the arguments that I'm not calling the functions, I'm just passing them.
I don't have computercraft handy right now or look up the functions but i know that you can use the function os.startTimer(t) that will cause an event in t seconds (I think it is seconds)
usage:
update_rate = 1
local _timer = os.startTimer(update_rate)
while true do
local event = os.pullEvent()
if event == _timer then
--updte_screen()
_timer = os.startTimer(update_rate)
elseif event == --some oter events you want to take action for
--action()
end
end
note: the code is not tested and I didn't use computercraft in quite a while so pleas correct me if i did a mistake.
Hi I want my lua code in Computercraft to allow the user to turn the redstone signal on/off by right clicking on a monitor on top, but I can't get it to work.
monitor = peripheral.wrap("top")
monitor.clear()
monitor.setTextColor(colors.red)
monitor.setCursorPos(1, 1)
monitor.setTextScale(1)
monitor.write("Hello")
function rubber()
monitor.setCursorPos(1, 2)
monitor.clearLine()
if rs.getOutput("right", true) then
monitor.write("Rubber farm is on")
elseif rs.getOutput("right", false) then
monitor.write("Rubber farm is off")
end
local event = { os.pullEvent() }
if event == "monitor_touch" then
if rs.getOutput("right") == true then
rs.setOutput("right", false)
else
rs.setOutput("right", true)
end
else
write("test")
end
rubber()
end
Right now all it displays is 'hello' and I don't know how to fix it, anyone know how? Also I'm a beginner at Lua so I've probably made some pretty simple mistakes. Thanks
local event = { os.pullEvent() }
if event == "monitor_touch" then
os.pullEvent returns a tuple. In your code, you're packing this tuple into a table. That's fine, but you then compare that table to a string. Tables can't be equal to strings - they're a table. Either don't pack the tuple into a table, and keep the first return value (the type):
local event = os.pullEvent()
if event == "monitor_touch" then
Or extract the first element when comparing
local event = { os.pullEvent() }
if event[1] == "monitor_touch" then
The problem is you wanted to have that function infinitly looping, but you have not called your function outside your function.... also you should look into using while loops
while true do
//stuff here
end
just add
rubber()
to the last line after your last end tag.
You have to call the function.
rubber()
You need to close your function
function rubber()
monitor.setCursorPos(1,1)
monitor.clearLine()
end
The end is it you need to make this little word
this is a simple fix, simply add rubber() after you finish the function rubber, cause while you have created the function rubber, you have not called for it to start yet.
The "monitor_touch" event is what you should be using. Also, make sure the monitor you are using is an advanced monitor (the one with the yellow border).
If you need help in understanding the event, check out this page: http://computercraft.info/wiki/Monitor_touch_(event)
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, ...)
-- ...