Thread Tools Display Modes
09-05-08, 01:58 PM   #1
SydneyBarringer
A Murloc Raider
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 7
Killing Blows

Hi. I'm trying to make a test addon (it will lead to something else eventually) that shows who kills who in, say, arena. Every kill relating to your party somehow (either they killed someone or someone killed them) would pop up on your screen saying who killed who and their classes.

For example,
"BobDaRogue (Rogue) has killed BernieTheMage (Mage)"

I hardly understand COMBAT_LOG_EVENT_UNFILTERED, but I think I know how to make the mod tell me when I land a killing blow, but I don't know how to make it fetch the names or classes. Could anyone help?

Thanks,
-Sydney Barringer
  Reply With Quote
09-05-08, 02:36 PM   #2
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
The event is "PARTY_KILL". It's triggered even if you're alone.
Argument number 4 shows who killed him/her/it (sourceName) and argument number 7 show what was killed (destinationName).

And shame on you ... I had to kill a cute lvl 1 kitten for this.


See http://www.wowwiki.com/API_COMBAT_LOG_EVENT for more informations about the new COMBAT_LOG_EVENT... stuff.

Last edited by Duugu : 09-05-08 at 02:39 PM.
  Reply With Quote
09-06-08, 12:33 PM   #3
SydneyBarringer
A Murloc Raider
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 7
Originally Posted by Duugu View Post
The event is "PARTY_KILL". It's triggered even if you're alone.
Argument number 4 shows who killed him/her/it (sourceName) and argument number 7 show what was killed (destinationName).

And shame on you ... I had to kill a cute lvl 1 kitten for this.


See http://www.wowwiki.com/API_COMBAT_LOG_EVENT for more informations about the new COMBAT_LOG_EVENT... stuff.
So, assume I have a frame, and on said frame I have FontString1. I want FontString1 to say whatever Arg4 is. How do I do that?

And woah! You're the guy who made the Goblin Therapist! I <3 you!

Last edited by SydneyBarringer : 09-06-08 at 12:36 PM.
  Reply With Quote
09-06-08, 01:22 PM   #4
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
First you'll have to register the event
Code:
getglobal("yourframe"):RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
Then you need a event handler. This could be the code itself
Code:
getglobal("yourframe"):SetScript("OnEvent", function(self, event, ...) searchfortheeventstuffandall end)
or a reference to a separate function
Code:
function MyOwnEventHandlerFunction(event, ...)
	searchfortheeventstuffandall
end
getglobal("yourframe"):SetScript("OnEvent", function(self, event, ...) MyOwnEventHandlerFunction(event, ...) end)
Ok. Now you'll handle the event. But what's about the searchfortheeventstuffandall stuff?
Via both ways I described above you'll get a number of arguments (the three dots "...", which is a variable number of arguments, see http://www.lua.org/manual/5.1/manual.html#2.5.9 for more information).
You'll have to access the variable number of arguments and then you'll have to get args 4 and 7 out of them.
The easiest way to access the varargs is to assign them to local vars:
Code:
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 = ...
A more readable version would be:
Code:
local timestamp, event, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags = ...
But the var names doesn't matter at all.

Note: If you are lost at this point and you absolutely don't know what the heck I'm talking about I would kindly request you to learn some lua and programming basics first.
´
So ... you're not lost? great

The arguments that are passed for the COMBAT_LOG_EVENT_UNFILTERED event are described here: http://www.wowwiki.com/API_COMBAT_LOG_EVENT
The first 8 args are always the same (base parameters):
They are: timestamp event sourceGUID sourceName sourceFlags destGUID destName destFlags
First you'll need event (which must be "PARTY_KILL" as I described in my previous post).
Code:
if arg2 == "PARTY_KILL" then
If this is true, then someone is killed.
Just get who killed who and show it:
Code:
getglobal("yourfonstring"):SetText(arg4.." just killed "..arg7)

Last edited by Duugu : 09-06-08 at 01:31 PM.
  Reply With Quote
09-06-08, 02:58 PM   #5
SydneyBarringer
A Murloc Raider
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 7
I understand the concepts of what you've said. So don't worry, you're not dealing with a complete idiot.

However, I am a bit lost when it comes to the syntax of this code. In other words, "Yikes, where the heck do I put all this stuff?"
What am I supposed to be writing where you put "searchfortheeventstuffandall"? Is there something I'm completely missing here?

Here's what I've written so far
*warning, abysmal code ahead. I kinda suck at this stuff*
Code:
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 = ...
getglobal("Frame1"):SetScript("OnEvent", function(self, event, ...) searchfortheeventstuffandall end)

function Frame1_OnLoad()
	getglobal("Frame1"):RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
end

function Frame1_OnEvent()
	if (event=="COMBAT_LOG_EVENT_UNFILTERED") then
		if (arg2=="PARTY_KILL") then
			getglobal("FontString1"):SetText(arg4)
		end
	end
end
For now, I'm just printing the value of arg4 in FontString1.

As I said earlier, I understand what exactly should be going on in the program and I understand the concept of global and local variables. So I'm not completely lost. What exactly have I done wrong?

Oh, and thank you for all the help you've given me so far. I really appreciate it.
  Reply With Quote
09-06-08, 06:53 PM   #6
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Well ok ... I'll try to describe it step for step and as clear as possible. It's a lot of text, but I think it's important to clarify the concept behind this to understand what's going on.

Please excuse my bad english - it's late (and I can't sleep), it's very technical and english isn't my first language.

1. You will need a frame (that's already done ... Frame1)

2. You will have to register the event COMBAT_LOG_EVENT_UNFILTERED for that frame to get all the combat log data (done via Frame_OnLoad ... great)

3. You have to handle the triggered COMBAT_LOG_EVENT_UNFILTERED events. That's not done so far.
You must set the script handler for OnEvent to a function where the event is processed. The function you wrote for this is Frame1_OnEvent(). To set the script handler to this function you'll use getglobal("Frame1"):SetScript(), which expects as parameters the script handler you would like to set ("OnEvent) and the function which will process the event (your Frame1_OnEvent() function). Replace
Code:
getglobal("Frame1"):SetScript("OnEvent", function(self, event, ...) searchfortheeventstuffandall end)
with
Code:
getglobal("Frame1"):SetScript("OnEvent", Frame1_OnEvent)
Now every (registered) event is passed to and handled by your function Frame1_OnEvent().
But there's a problem. You placed the getglobal("Frame1"):SetScript() outside of any function. This means, it's executed if the lua file is loaded. At this time it could be, that the frame (Frame1) isn't there ... and then the code will fail.
To prevent this, it's better to set the OnEvent script handler inside of you OnLoad handler. OnLoad is triggered if the frame loads - which means the frame is definitely there. So move the line
Code:
getglobal("Frame1"):SetScript("OnEvent", Frame1_OnEvent)
into you OnLoad handler
Code:
function Frame1_OnLoad()
	getglobal("Frame1"):RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	getglobal("Frame1"):SetScript("OnEvent", Frame1_OnEvent)
end
4. Now the COMBAT_LOG_EVENT_UNFILTERED event is registered, and if it is triggered by wow it is passed to your OnEvent function.
For every triggered COMBAT_LOG_EVENT_UNFILTERED event there will be a lot of event data (source, destination ... the stuff I specified in my previous posts). These data will also be passed to your OnEvent function. It's now up to you to access and process the event data inside your OnEvent function. To access the data that is passed to your function you'll have to specify these data in your function header (function Frame1_OnEvent()). Unfortunately your current function header "function Frame1_OnEvent()" means "there is no data that is passed to this function". (or more specific: if there are any data we will not care about it *g*).
So if you know that there is data passed to your function (let's hypothetical say an event name and a ... timestamp) then you'll have to specify this. An example:
Code:
function Frame1_OnEvent(eventname, timestamp) 
end
But again there's a problem: You don't know how much data is passed with the COMBAT_LOG_EVENT_UNFILTERED to you function. Sometimes there are 15 values, sometimes only 8, and so on. Due to this you can't specify the passed data in your function header - you don't know how much data is passed. If you specify a function header like "function Frame1_OnEvent(eventname, timestamp)" and the COMBAT_LOG_EVENT_UNFILTERED passes ... let's say the values eventname, timestamp, SourceName, and DestinationName, in this order, then you function header "function Frame1_OnEvent(eventname, timestamp)" would be crap. Right? The correct function header would be "function Frame1_OnEvent(eventname, timestamp, SourceName, DestinationName)". Otherwise you will lose SourceName and DestinationName.
So the problem is: you don't know how many data is passed to you OnEvent function and you can't write a suitable function header.
To solve this problem there's a special lua expression: three dots (...)
This expression means "there is a unknown number of data passed to this function". Think about the three dots as a dynamic collection with all data that is passed to your function.
The first step in catching and processing the unknown number of data in your OnEvent function is to specify these unknown number of data in your function header:
Code:
function Frame1_OnEvent(...) 
end
Inside you function the three dots (...) expression now is a reference to the collection with all the passed event data. There are multiple ways to access the values in the ... collection. The easiest way is to assign the values to some local variables:
Code:
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 = ...
This assigns value number 1 in the three dots (...) collection to arg1, number 2 to arg2, and so on. If there are less than 8 values in the collection then the corresponding variables will be nil. If there are more than 8 values in the ... collection the rest of them is ignored.
Ok. Now you got at least the first 8 of the values of the event data that is passed to your OnEvent handler. In our case this is enough.

5. Process the event data
Now we have to care about WHICH data is passed to our function. We got up to 8 values. But what do the stand for?
The fist and the second value that is passed with an event are always a reference to the frame the event is triggered for (usually named "self") and the WoW (!) event that is triggered (must be COMBAT_LOG_EVENT_UNFILTERED in our case, because we didn't register any other event).
The following values (3, 4, 5, and so on) are the combat log data. For every combat log event there are at least 8 additional values. These values are:
  • timestamp,
  • combatlogEvent (mind!!! this is not the same as the WoW event COMBAT_LOG_EVENT_UNFILTERED - it's the combat log event),
  • sourceGUID,
  • sourceName,
  • sourceFlags,
  • destGUID,
  • destName,
  • destFlags
So we know, the values in our three dots (...) collection will be from 1 to 10:
  • self,
  • wowEvent(!),
  • timestamp,
  • combatlogEvent(!),
  • sourceGUID,
  • sourceName,
  • sourceFlags,
  • destGUID,
  • destName,
  • destFlags
To have a more readable code we could now change the line
Code:
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 = ...
into
Code:
local self, wowEvent, timestamp, combatlogEvent, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags = ...
You code now looks like that:
Code:
function Frame1_OnEvent(...) 
	local self, wowEvent, timestamp, combatlogEvent, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags = ...
end
With this it's easy to parse the data. We don't care about "self" and "wowEvent" (we don't need a reference to the frame, and we KNOW that the WoW event is COMBAT_LOG_EVENT_UNFILTERED). We need the combat log (!) event: combatlogEvent
It has to be PARTY_KILL - which means someone or something just died.
Code:
function Frame1_OnEvent(...) 
	local self, wowEvent, timestamp, combatlogEvent, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags = ...
	if combatlogEvent == "PARTY_KILL" then

	end
end
And finally if our combat log event is triggered, we need the names of the victim and the killer: sourceName and destName. So the complete OnEvent handler is:
Code:
function Frame1_OnEvent(...) 
	local self, wowEvent, timestamp, combatlogEvent, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags = ...
	if combatlogEvent == "PARTY_KILL" then
		getglobal("FontString1"):SetText(sourceName.." killed "..destName)
	end
end

After all this the complete should be:
Code:
function Frame1_OnEvent(...) 
	local self, wowEvent, timestamp, combatlogEvent, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags = ...
	if combatlogEvent == "PARTY_KILL" then
		getglobal("FontString1"):SetText(sourceName.." killed "..destName)
	end
end
function Frame1_OnLoad()
	getglobal("Frame1"):RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	getglobal("Frame1"):SetScript("OnEvent", Frame1_OnEvent)
end

Last edited by Duugu : 09-06-08 at 06:55 PM.
  Reply With Quote
09-13-08, 10:08 AM   #7
SydneyBarringer
A Murloc Raider
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 7
Sorry for not responding in so long. School's started up again and I've been working all week.

Thank you so much for your help. I think I understand it now.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Killing Blows


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off