How to catch the event of a instant or casting spell? - lua

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.

Related

How to load WoW addon after CLUB_STREAM_SUBSCRIBED event?

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");

How to run a Function on a Player GMOD DarkRP Lua

I am trying to make a muting script that doesn't let players talk. At the moment I am at telling which player in the script with no commands but I cant work out or find how to run this function that I created on a specific player, not just mute the entire server.
sv_mute.lua:
util.AddNetworkString( "mute_message" )
ismuted == false
targetPlayer == "Xx_Player_xX"
function checkmute()
function SendMessage( ply, txt, pub )
net.Start( "mute_message" )
net.WriteString( "YOU ARE MUTED, SHUT UP" )
net.Send( ply )
return ""
end
hook.Add( "PlayerSay", "SendMessage", SendMessage, )
end
Player:checkmute(()targetPlayer)
cl_mute.lua:
function ReceiveMessage()
local txt = net.ReadString()
chat.AddText( Color( 0, 255, 0), txt)
end
I have so far got to using Player:checkmute(()targetPlayer) but I assume this is wrong
So at first a few mistakes I have seen on a first quick look.
You defined a function without a parameter but you try to call it with one
You did not used the tools Garry gave you already to send messages to players
Things we will be using to achieve your desired task
GM:PlayerSay( Player sender, string text, boolean teamChat )
Player:PrintMessage( number type, string message )
The solution
-- sv_mute.lua
-- a list of muted players, you need to get them from somewhere (not part of this answer)
mutedPlayers = {
"StupidMan" = true,
"AnnoyingKid" = true,
"ExGirlfriend" = true
}
-- the function that will check if a user is muted
local function checkMuted(--[[ string ]] playername)
return mutedPlayers[playername]
-- you probably need to change the code to something else
-- based on how you store your muted players
end
hook.Add("PlayerSay", "VosemMute_PlayerSay", function(sender, message, teamChat)
if ( checkMuted(sender:GetName()) ) then
sender.PrintMessage(HUD_PRINTTALK, "You are muted!")
return "" -- this will suppress the message
end
end)
Some helpful links
HUD Enumerations (HUD_PRINTTALK)
Player:GetName()
hook.Add( string eventName, any identifier, function func )
Garry's Mod Wiki
Lua Reference Manual (sadly i do not know which lua version is used by gmod)
Disclaimer
This code is completely untested and written of my mind. If this does not work and throws some errors let me know that. I'll correct it then.

Garry's Mod - Props won't spawn after launching Lua script

I have a test server for gmod. I've coded a script that works excellent when I launch it, but there is a lot of downsides with it.
I've tried to code a script that will simply change the users speed if they type a command like "!speed fast", or "!speed normal". It looks like this:
table = {}
table[0]="!help"
table[1]="!speed normal"
table[2]="!speed fast"
table[3]="!speed sanic"
hook.Add("PlayerSay", "Chat", function(ply, message, teamchat)
if message == "!speed normal" then
GAMEMODE:SetPlayerSpeed(ply, 250, 500 )
elseif message == "!speed fast" then
GAMEMODE:SetPlayerSpeed(ply, 1000, 2000 )
elseif message == "!speed sanic" then
GAMEMODE:SetPlayerSpeed(ply, 10000, 20000)
elseif message == "!help" then
for key, value in pairs(table) do
PrintMessage( HUD_PRINTTALK, value)
end
end
end)
As you can see the script change the users speed if they either type "!speed normal", "!speed fast" or "!speed sanic" in chat. The script also contains a table of every command, and it will be shown if the user type "!help" in chat.
When I launch the script it works excellent, but if I try to spawn a prop after I've launched it, the prop won't spawn. Even when I spawn a prop first, then launch the script and try to "undo" the prop, the "undo" function won't work! The script makes Sandbox gamemode completely useless, because you can't even spawn props!
I've tried to search a little bit around on the internet first, but I haven't stumbled across something like this yet, so I hope someone got the solution! Please help
My guess is that this is happening because you are overwriting the global table. The table library contains helper functions for tables. Try renaming your table table to something else, like commands. I would also suggest you declare it as local commands so it does not replace any other global, so it does not interfere with anything else, like other scripts or library.
Also, as extra tips, lua tables are indexed with 1, So you could declare your renamed table as:
local commands = {
"!help",
"!speed normal",
"!speed fast",
"!speed sanic",
}
You could then iterate over it with a normal for:
for index = 1, #commands do
PrintMessage(HUD_PRINTTALK, commands[index])
end
I think this makes it a bit cleaner, in my opinion.

Having trouble with some computercraft/lua code

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)

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