1 QuestHelper_File
["collect_loot.lua"] = "Development Version"
2 QuestHelper_Loadtime
["collect_loot.lua"] = GetTime()
4 if not UNIT_SKINNABLE_BOLTS
then return end -- This just drops us out early if the user is using 2.4.3, otherwise we get a weird error message that isn't the one we're intending to get.
6 local debug_output
= false
7 if QuestHelper_File
["collect_loot.lua"] == "Development Version" then debug_output
= true end
21 local members_count
= 0
22 local members_refs
= {} -- "raid6" and the like
24 local function MembersUpdate()
25 -- We want to keep track of exactly who is in a group with this player, so we can watch for combat messages involving them, so we can see who's been tapped, so we can record the right deaths, so we can know who the player should be able to loot.
31 --QuestHelper:TextOut("MU start")
32 members
= {} -- we burn a table every time this updates, but whatever
34 if GetNumRaidMembers() > 0 then
37 local ite
= string.format("raid%d", i
)
38 local gud
= UnitGUID(ite
)
41 table.insert(members_refs
, ite
)
42 --QuestHelper:TextOut(string.format("raid member %s added", UnitName(ite)))
45 elseif GetNumPartyMembers() > 0 then
48 local ite
= string.format("party%d", i
)
49 local gud
= UnitGUID(ite
)
52 table.insert(members_refs
, ite
)
53 --QuestHelper:TextOut(string.format("party member %s added", UnitName(ite)))
56 members
[UnitGUID("player")] = true
57 table.insert(members_refs
, "player")
58 --QuestHelper:TextOut(string.format("player %s added", UnitName("player")))
61 if UnitGUID("player") then members
[UnitGUID("player")] = true end -- it's possible that we haven't logged in entirely yet
62 table.insert(members_refs
, "player")
63 --QuestHelper:TextOut(string.format("player %s added as %s", UnitName("player"), tostring(UnitGUID("player"))))
67 if GetLootMethod() == "master" and not alone
then members
= {} members_refs
= {} end -- We're not going to bother trying to deal with master loot right now - it's just too different and I just don't care enough.
69 for _
, _
in pairs(members
) do members_count
= members_count
+ 1 end -- lulz
72 local MS_TAPPED_US
= 1
73 local MS_TAPPED_US_TRIVIAL
= 2
74 local MS_TAPPED_OTHER
= 3
75 local MS_TAPPED_LOOTABLE
= 4
76 local MS_TAPPED_LOOTABLE_TRIVIAL
= 5
77 local MS_TAPPED_LOOTED
= 6
79 local last_cleanup
= GetTime()
81 local monsterstate
= {}
82 local monsterrefresh
= {}
83 local monstertimeout
= {}
85 -- This all does something quite horrible.
86 -- Some monsters don't become lootable when they're killed and didn't drop anything. We need to record this so we can get real numbers for them.
87 -- Unfortunately, we can't just record when "something" is killed. We have to record when "our group" killed it, so we know that there *was* a chance of looting it.
88 -- As such, we need to check for monster deaths that the player may never have actually targeted. It gets, to put it mildly, grim, and unfortunately we'll never be able to solve it entirely.
89 -- Worse, we need to *not* record item drops for things that we never actually "saw" but that were lootable anyway, because if we do, we bias the results towards positive (i.e. if we AOE ten monsters down, and two of them drop, and we loot those, that's 2/2 if we record the drops, and 0/0 if we don't, while what we really want is 2/10. 0/0 is at least "not wrong".)
90 -- On top of this, we want to avoid looting "discarded items", but unfortunately there's no real good way to determine this. Welp.
92 -- Here's a little bottleneck - we're going to try to only do one scan per second. Fingers crossed.
94 local function CombatLogEvent(_
, event
, sourceguid
, _
, _
, destguid
, _
, _
, _
, spellname
)
95 -- There's many things that are handled here.
96 -- First, if there's any damage messages coming either to or from a party member, we check to see if that monster is tapped by us. If it's tapped, we cache the value for 15 seconds, expiring entirely in 30.
97 -- Second, there's the Death message. If it's tapped by us, increases the kill count by 1/partymembers and changes its state to lootable.
98 if event
~= "UNIT_DIED" then
99 if last_scan
> GetTime() then return end -- welp
101 -- Something has been attacked by something, maybe.
102 if not string.find(event
, "_DAMAGE$") then return end -- We only care about something punching something else.
105 if members
[sourceguid
] then
108 elseif members
[destguid
] then
111 end -- If one of the items is in our party, the other is our target.
113 if not target
then return end -- If we don't have a target, then nobody is in our party, and we don't care.
115 if monsterrefresh
[target
] and monsterrefresh
[target
] > GetTime() then return end -- we already have fresh data, so we're good
117 -- Now comes the tricky part. We can't just look at the target because we're not allowed to target by GUID. So we iterate through all the party/raid members and hope *someone* has it targeted. Luckily, we can stop once we find someone who does.
119 for _
, v
in pairs(members_refs
) do
120 targ
= v
.. "target" if UnitGUID(targ
) == target
then break end
123 last_scan
= GetTime() + 1
126 --monsterrefresh[target] = GetTime() + 5
127 --monstertimeout[target] = GetTime() + 5
129 end -- Well, nobody seems to be targeting it. That's . . . odd, and annoying. We were thinking of tossing on a 5-second timeout. But we didn't, because we decided the global one-second lockout might help. So we'll do that for now.
131 -- Okay. So we know who's targeting it. Now, let's see who has it tapped, if anyone.
132 if not UnitIsTapped(targ
) then
133 -- Great. Nobody is. That is just *great*. Look how exuberant I feel at this moment. You know what? 5-second timeout.
134 monsterstate
[target
] = nil
135 monsterrefresh
[target
] = GetTime() + 5
136 monstertimeout
[target
] = GetTime() + 5
137 if debug_output
then QuestHelper
:TextOut(string.format("Monster ignorified")) end
139 -- We know someone is, so we're going to set up our caching . . .
140 monsterrefresh
[target
] = GetTime() + 15
141 monstertimeout
[target
] = GetTime() + 30
142 monsterstate
[target
] = (UnitIsTappedByPlayer(targ
)) and (not UnitIsTrivial(targ
) and MS_TAPPED_US
or MS_TAPPED_US_TRIVIAL
) or MS_TAPPED_OTHER
-- and figure out if it's us. Or if it's trivial. We somewhat-ignore it if it's trivial, since it's much less likely to be looted and that could throw off our numbers
143 if debug_output
then QuestHelper
:TextOut(string.format("Monster %s set to %d, %s, %s", target
, monsterstate
[target
], tostring(UnitIsTappedByPlayer(targ
)), tostring(UnitIsTrivial(targ
)))) end
148 -- It's dead. Hooray!
150 if monsterstate
[destguid
] and monstertimeout
[destguid
] > GetTime() and (monsterstate
[destguid
] == MS_TAPPED_US
or monsterstate
[destguid
] == MS_TAPPED_US_TRIVIAL
) and members_count
> 0 then -- yaaay
151 local type = GetMonsterType(destguid
)
152 if not QHC
.monster
[type] then QHC
.monster
[type] = {} end
153 if monsterstate
[destguid
] == MS_TAPPED_US
then
154 QHC
.monster
[type].kills
= (QHC
.monster
[type].kills
or 0) + 1 / members_count
-- Hopefully, most people loot their kills. Divide by members_count 'cause there's a 1/members chance that we get to loot. We'll flag the loot count some other way if it was a trivial monster.
157 monsterstate
[destguid
] = (monsterstate
[destguid
] == MS_TAPPED_US
and MS_TAPPED_LOOTABLE
or MS_TAPPED_LOOTABLE_TRIVIAL
)
158 monsterrefresh
[destguid
] = GetTime() + 600
159 monstertimeout
[destguid
] = GetTime() + 600
160 --QuestHelper:TextOut(string.format("Tapped monster %s slain, set to lootable", destguid))
162 monsterstate
[destguid
] = nil
163 monsterrefresh
[destguid
] = nil
164 monstertimeout
[destguid
] = nil
165 --QuestHelper:TextOut(string.format("Untapped monster %s slain, cleared", destguid))
172 skintypes
[UNIT_SKINNABLE_ROCK
] = "mine"
173 skintypes
[UNIT_SKINNABLE_HERB
] = "herb"
174 skintypes
[UNIT_SKINNABLE_BOLTS
] = "eng"
175 skintypes
[UNIT_SKINNABLE_LEATHER
] = "skin"
177 local function SkinnableflagsTooltipy(self
, ...)
178 --QuestHelper:TextOut("tooltipy")
179 if UnitExists("mouseover") and UnitIsVisible("mouseover") and not UnitIsPlayer("mouseover") and not UnitPlayerControlled("mouseover") and UnitIsDead("mouseover") then
180 local guid
= UnitGUID("mouseover")
181 --QuestHelper:TextOut("critar")
182 if not monsterstate
[guid
] or monsterstate
[guid
] ~= MS_TAPPED_LOOTED
or monsterrefresh
[guid
] > GetTime() then return end
183 --QuestHelper:TextOut("runin")
185 local cid
= GetMonsterType(guid
)
189 local lines
= GameTooltip
:NumLines()
191 --QuestHelper:TextOut(_G["GameTooltipTextLeft" .. tostring(i)]:GetText())
192 local skeen
= skintypes
[_G
["GameTooltipTextLeft" .. tostring(i
)]:GetText()]
193 if skeen
then QuestHelper
: Assert(not skintype
) skintype
= skeen
end
196 if not QHC
.monster
[cid
] then QHC
.monster
[cid
] = {} end
197 local qhci
= QHC
.monster
[cid
]
199 for _
, v
in pairs(skintypes
) do
200 if v
== skintype
then
201 --QuestHelper:TextOut(v .. "_yes")
202 qhci
[v
.. "_yes"] = (qhci
[v
.. "_yes"] or 0) + 1
204 --QuestHelper:TextOut(v .. "_no")
205 qhci
[v
.. "_no"] = (qhci
[v
.. "_no"] or 0) + 1
211 -- Logic behind this module:
212 -- Watch for the spell to be sent
213 -- Watch for it to start
214 -- Check out the combat log and see what GUID we get
215 -- If the GUID is null, we're targeting an object, otherwise, we're targeting a critter
216 -- Wait for spell to succeed
217 -- If anything doesn't synch up, or the spell is interrupted, nil out all these items.
218 -- We've got a little special case for pickpocketing, because people often use macros, so we detect that case specifically.
222 local PP_PHASE_COMPLETE
224 local pickpocket_phase
= PP_PHASE_IDLE
225 local pickpocket_target
226 local pickpocket_otarget_guid
227 local pickpocket_timestamp
229 local pickpocket_name
= GetSpellInfo(921) -- this is the pickpocket spell ID
231 local function pp_reset()
232 pickpocket_target
, pickpocket_otarget_guid
, pickpocket_timestamp
, pickpocket_phase
= nil, nil, nil, PP_PHASE_IDLE
236 local function PPSent(player
, spell
, _
, target
)
237 if player
~= "player" then return end
238 if spell
~= pickpocket_name
then return end
239 if UnitName("target") ~= target
then return end -- DENY
241 pickpocket_timestamp
, pickpocket_target
, pickpocket_otarget_guid
, pickpocket_phase
= GetTime(), target
, UnitGUID("target"), PP_PHASE_SENT
244 local function PPSucceed(player
, spell
, rank
)
245 if player
~= "player" then return end
246 if spell
~= pickpocket_name
then return end
248 if pickpocket_phase
~= PP_PHASE_SENT
and (not pickpocket_otarget_guid
or last_timestamp
+ 1 < GetTime()) then
253 pickpocket_timestamp
, pickpocket_phase
= GetTime(), PP_PHASE_COMPLETE
257 -- This segment deals with openable containers
260 local touched_timestamp
262 local function ItemLock(bag
, slot
)
263 if not bag
or not slot
then return end -- probably changing equipment
265 local _
, _
, locked
= GetContainerItemInfo(bag
, slot
)
266 --QuestHelper:TextOut(string.format("trying lock %s", tostring(locked)))
268 touched_itemid
= GetItemType(GetContainerItemLink(bag
, slot
))
269 --[[QuestHelper:TextOut(string.format("trying lock %s", tostring(touched_itemid)))
270 QuestHelper:TextOut(string.format("trying lock %s", tostring(type(touched_itemid))))
271 QuestHelper:TextOut(string.format("trying lock %s", tostring(QHC.item[touched_itemid].open_yes)))
272 QuestHelper:TextOut(string.format("trying lock %s", tostring(QHC.item[touched_itemid].open_no)))]]
273 touched_timestamp
= GetTime()
274 if not QHC
.item
[touched_itemid
] or (QHC
.item
[touched_itemid
].open_yes
or 0) <= (QHC
.item
[touched_itemid
].open_no
or 0) then
276 touched_timestamp
= nil
280 touched_timestamp
= nil
285 -- Here's the segment for longer spells. There aren't any instant spells we currently care about, besides pickpocketing. This will probably change eventually (arrows in the DK starting zone?)
287 local LAST_PHASE_IDLE
= 0
288 local LAST_PHASE_SENT
= 1
289 local LAST_PHASE_START
= 2
290 local LAST_PHASE_COMBATLOG
= 3
291 local LAST_PHASE_COMPLETE
= 4
293 local last_phase
= LAST_PHASE_IDLE
297 local last_target_guid
299 local last_otarget_guid
301 local last_succeed
= false
302 local last_succeed_trade
= GetTime()
304 local gathereffects
= {}
306 gathereffects
[GetSpellInfo(51306)] = {token
= "eng", noclog
= true}
307 gathereffects
[GetSpellInfo(32606)] = {token
= "mine"}
308 gathereffects
[GetSpellInfo(2366)] = {token
= "herb"}
309 gathereffects
[GetSpellInfo(8613)] = {token
= "skin"}
310 gathereffects
[GetSpellInfo(21248)] = {token
= "open", noclog
= true}
311 gathereffects
[GetSpellInfo(30427)] = {token
= "extract", noclog
= true} -- not a loot window, so it won't really work, but hey
312 gathereffects
[GetSpellInfo(13262)] = {token
= "de", noclog
= true, ignore
= true}
313 gathereffects
[GetSpellInfo(31252)] = {token
= "prospect", noclog
= true, ignore
= true}
314 gathereffects
[GetSpellInfo(51005)] = {token
= "mill", noclog
= true, ignore
= true}
318 local function last_reset()
319 last_timestamp
, last_spell
, last_rank
, last_target
, last_target_guid
, last_otarget
, last_otarget_guid
, last_succeed
, last_phase
= nil, nil, nil, nil, nil, nil, false, LAST_PHASE_IDLE
323 -- This all doesn't work with instant spells. Luckily, I don't care about instant spells (yet).
324 local function SpellSent(player
, spell
, rank
, target
)
325 if player
~= "player" then return end
327 last_timestamp
, last_spell
, last_rank
, last_target
, last_target_guid
, last_otarget
, last_otarget_guid
, last_succeed
, last_phase
= GetTime(), spell
, rank
, target
, nil, UnitName("target"), UnitGUID("target"), false, LAST_PHASE_SENT
329 if last_otarget
and last_otarget
~= last_target
then last_reset() return end
331 --QuestHelper:TextOut(string.format("ss %s", spell))
334 local function SpellStart(player
, spell
, rank
)
335 if player
~= "player" then return end
337 if spell
~= last_spell
or rank
~= last_rank
or last_target_guid
or last_phase
~= LAST_PHASE_SENT
or last_timestamp
+ 1 < GetTime() then
340 --QuestHelper:TextOut(string.format("sst %s", spell))
341 last_timestamp
, last_phase
= GetTime(), LAST_PHASE_START
345 local function SpellCombatLog(_
, event
, sourceguid
, _
, _
, destguid
, _
, _
, _
, spellname
)
346 if event
~= "SPELL_CAST_START" then return end
348 if sourceguid
~= UnitGUID("player") then return end
350 --QuestHelper:TextOut(string.format("cle_ss enter %s %s %s %s", tostring(spellname ~= last_spell), tostring(not last_target), tostring(not not last_target_guid), tostring(last_timestamp + 1 < GetTime())))
352 if spellname
~= last_spell
or not last_target
or last_target_guid
or last_timestamp
+ 1 < GetTime() then
357 --QuestHelper:TextOut("cle_ss enter")
359 if last_phase
~= LAST_PHASE_START
then
364 --QuestHelper:TextOut(string.format("cesst %s", spellname))
365 last_timestamp
, last_target_guid
, last_phase
= GetTime(), destguid
, LAST_PHASE_COMBATLOG
367 if last_target_guid
== "0x0000000000000000" then last_target_guid
= nil end
368 if last_target_guid
and last_target_guid
~= last_otarget_guid
then last_reset() return end
371 local function SpellSucceed(player
, spell
, rank
)
372 if player
~= "player" then return end
374 if gathereffects
[spell
] then last_succeed_trade
= GetTime() end
376 --QuestHelper:TextOut(string.format("sscu enter %s %s %s %s %s", tostring(last_spell), tostring(last_target), tostring(last_rank), tostring(spell), tostring(rank)))
378 if not last_spell
or not last_target
or last_spell
~= spell
or last_rank
~= rank
then
383 --QuestHelper:TextOut("sscu enter")
385 if gathereffects
[spell
] and gathereffects
[spell
].noclog
then
386 if last_phase
~= LAST_PHASE_START
or last_timestamp
+ 10 < GetTime() then
391 if last_phase
~= LAST_PHASE_COMBATLOG
or last_timestamp
+ 10 < GetTime() then
397 --QuestHelper:TextOut(string.format("sscu %s, %d, %s, %s", spell, last_phase, tostring(last_phase == LAST_PHASE_SENT), tostring((last_phase == LAST_PHASE_SENT) and LAST_PHASE_SHORT_SUCCEEDED)))
398 last_timestamp
, last_succeed
, last_phase
= GetTime(), true, LAST_PHASE_COMPLETE
399 --QuestHelper:TextOut(string.format("last_phase %d", last_phase))
401 --[[if last_phase == LAST_PHASE_COMPLETE then
402 QuestHelper:TextOut(string.format("spell succeeded, casting %s %s on %s/%s", last_spell, last_rank, tostring(last_target), tostring(last_target_guid)))
406 local function SpellInterrupt(player
, spell
, rank
)
407 if player
~= "player" then return end
409 -- I don't care what they were casting, they're certainly not doing it now
410 --QuestHelper:TextOut(string.format("si %s", spell))
414 local function LootOpened()
416 local targetguid
= UnitGUID("target")
418 -- We're cleaning up the monster charts here, on the theory that if someone is looting, they're okay with a tiny lag spike.
419 if last_cleanup
+ 300 < GetTime() then
421 for k
, v
in pairs(monstertimeout
) do
422 if v
< GetTime() then table.insert(cleanup
, k
) end
425 for _
, v
in pairs(cleanup
) do
426 monsterstate
[v
] = nil
427 monsterrefresh
[v
] = nil
428 monstertimeout
[v
] = nil
432 -- First off, we try to figure out where the hell these items came from.
437 if IsFishingLoot() then
439 if debug_output
then QuestHelper
:TextOut("Fishing loot") end
441 if not QHC
.fishing
[loc
] then QHC
.fishing
[loc
] = {} end
442 spot
= QHC
.fishing
[loc
]
445 elseif pickpocket_phase
== PP_PHASE_COMPLETE
and pickpocket_timestamp
and pickpocket_timestamp
+ 1 > GetTime() and targetguid
== pickpocket_otarget_guid
then
446 if debug_output
then QuestHelper
:TextOut(string.format("Pickpocketing from %s/%s", pickpocket_target
, UnitName("target"), targetguid
)) end
447 local mid
= GetMonsterType(targetguid
)
448 if not QHC
.monster
[mid
] then QHC
.monster
[mid
] = {} end
449 spot
= QHC
.monster
[mid
]
452 elseif last_phase
== LAST_PHASE_COMPLETE
and gathereffects
[last_spell
] and last_timestamp
+ 1 > GetTime() then
453 local beef
= string.format("%s/%s %s/%s", tostring(last_target
), tostring(last_target_guid
), tostring(last_otarget
), tostring(last_otarget_guid
))
455 if gathereffects
[last_spell
].ignore
then return end
457 prefix
= gathereffects
[last_spell
].token
459 -- this one is sort of grim actually
460 -- If we have an last_otarget_guid, it's the right one, and it's a monster
461 -- If we don't, use last_target, and it's an object
462 -- This is probably going to be buggy. Welp.
463 if last_otarget_guid
then
464 if debug_output
then QuestHelper
:TextOut(string.format("%s from monster %s", gathereffects
[last_spell
].token
, beef
)) end
465 local mid
= GetMonsterType(last_otarget_guid
)
466 if not QHC
.monster
[mid
] then QHC
.monster
[mid
] = {} end
467 spot
= QHC
.monster
[mid
]
469 if debug_output
then QuestHelper
:TextOut(string.format("%s from object %s", gathereffects
[last_spell
].token
, beef
)) end
470 if not QHC
.object
[last_target
] then QHC
.object
[last_target
] = {} end
471 spot
= QHC
.object
[last_target
]
474 elseif touched_timestamp
and touched_timestamp
+ 1 > GetTime() then
475 -- Opening a container, possibly
476 if debug_output
then QuestHelper
:TextOut(string.format("Opening container %d", touched_itemid
)) end
477 if not QHC
.item
[touched_itemid
] then QHC
.item
[touched_itemid
] = {} end
478 spot
= QHC
.item
[touched_itemid
]
481 elseif targetguid
and (monsterstate
[targetguid
] == MS_TAPPED_LOOTABLE
or monsterstate
[targetguid
] == MS_TAPPED_LOOTABLE_TRIVIAL
) and monstertimeout
[targetguid
] > GetTime() and (not pickpocket_timestamp
or pickpocket_timestamp
+ 5 < GetTime()) and (not last_timestamp
or last_timestamp
+ 5 < GetTime()) and (last_succeed_trade
+ 5 < GetTime()) then -- haha holy shit
482 -- Monster is lootable, so we loot the monster. Should we check to see if it's dead first? Probably.
483 if debug_output
then QuestHelper
:TextOut(string.format("%s from %s/%s", (monsterstate
[targetguid
] == MS_TAPPED_LOOTABLE
and "Monsterloot" or "Trivial monsterloot"), UnitName("target"), targetguid
)) end
485 local mid
= GetMonsterType(targetguid
)
486 if not QHC
.monster
[mid
] then QHC
.monster
[mid
] = {} end
487 spot
= QHC
.monster
[mid
]
488 if monsterstate
[targetguid
] == MS_TAPPED_LOOTABLE
then
490 elseif monsterstate
[targetguid
] == MS_TAPPED_LOOTABLE_TRIVIAL
then
491 prefix
= "loot_trivial" -- might be a better way to do this, but we'll see
494 monsterstate
[targetguid
] = MS_TAPPED_LOOTED
495 monstertimeout
[targetguid
] = GetTime() + 300
496 monsterrefresh
[targetguid
] = GetTime() + 2
498 if debug_output
then QuestHelper
:TextOut("Who knows") end -- ugh
500 if not QHC
.worldloot
[loc
] then QHC
.worldloot
[loc
] = {} end
501 spot
= QHC
.worldloot
[loc
]
510 for i
= 1, GetNumLootItems() do
511 _
, name
, quant
, _
= GetLootSlotInfo(i
)
512 link
= GetLootSlotLink(i
)
515 local _
, _
, amount
= string.find(name
, Patterns
.GOLD_AMOUNT
)
516 if amount
then items
.gold
= items
.gold
+ tonumber(amount
) * 10000 end
518 local _
, _
, amount
= string.find(name
, Patterns
.SILVER_AMOUNT
)
519 if amount
then items
.gold
= items
.gold
+ tonumber(amount
) * 100 end
521 local _
, _
, amount
= string.find(name
, Patterns
.COPPER_AMOUNT
)
522 if amount
then items
.gold
= items
.gold
+ tonumber(amount
) * 1 end
524 local itype
= GetItemType(link
)
525 items
[itype
] = (items
[itype
] or 0) + quant
529 spot
[prefix
.. "_count"] = (spot
[prefix
.. "_count"] or 0) + 1
530 if not spot
[prefix
.. "_loot"] then spot
[prefix
.. "_loot"] = {} end
531 local pt
= spot
[prefix
.. "_loot"]
532 for k
, v
in pairs(items
) do
533 if v
> 0 then pt
[k
] = (pt
[k
] or 0) + v
end
537 function QH_Collect_Loot_Init(QHCData
, API
)
540 if not QHC
.monster
then QHC
.monster
= {} end
541 if not QHC
.worldloot
then QHC
.worldloot
= {} end
542 if not QHC
.fishing
then QHC
.fishing
= {} end
543 if not QHC
.item
then QHC
.item
= {} end
545 API
.Registrar_EventHook("PLAYER_ENTERING_WORLD", MembersUpdate
)
546 API
.Registrar_EventHook("RAID_ROSTER_UPDATE", MembersUpdate
)
547 API
.Registrar_EventHook("PARTY_MEMBERS_CHANGED", MembersUpdate
)
548 API
.Registrar_EventHook("COMBAT_LOG_EVENT_UNFILTERED", CombatLogEvent
)
550 API
.Registrar_EventHook("UPDATE_MOUSEOVER_UNIT", SkinnableflagsTooltipy
)
552 API
.Registrar_EventHook("UNIT_SPELLCAST_SENT", PPSent
)
553 API
.Registrar_EventHook("UNIT_SPELLCAST_SUCCEEDED", PPSucceed
)
555 API
.Registrar_EventHook("ITEM_LOCK_CHANGED", ItemLock
)
557 API
.Registrar_EventHook("UNIT_SPELLCAST_SENT", SpellSent
)
558 API
.Registrar_EventHook("UNIT_SPELLCAST_START", SpellStart
)
559 API
.Registrar_EventHook("COMBAT_LOG_EVENT_UNFILTERED", SpellCombatLog
)
560 API
.Registrar_EventHook("UNIT_SPELLCAST_SUCCEEDED", SpellSucceed
)
561 API
.Registrar_EventHook("UNIT_SPELLCAST_INTERRUPTED", SpellInterrupt
)
563 API
.Registrar_EventHook("LOOT_OPENED", LootOpened
)
565 MembersUpdate() -- to get self, probably won't work but hey
567 GetMonsterUID
= API
.Utility_GetMonsterUID
568 GetMonsterType
= API
.Utility_GetMonsterType
569 GetItemType
= API
.Utility_GetItemType
570 QuestHelper
: Assert(GetMonsterUID
)
571 QuestHelper
: Assert(GetMonsterType
)
572 QuestHelper
: Assert(GetItemType
)
574 Patterns
= API
.Patterns
575 API
.Patterns_RegisterNumber("GOLD_AMOUNT")
576 API
.Patterns_RegisterNumber("SILVER_AMOUNT")
577 API
.Patterns_RegisterNumber("COPPER_AMOUNT")
579 GetLoc
= API
.Callback_LocationBolusCurrent
580 QuestHelper
: Assert(GetLoc
)
582 -- What I want to know is whether it was tagged by me or my group when dead
583 -- Check target-of-each-groupmember? Once we see him tapped once, and by us, it's probably sufficient.
587 COMBAT_LOG_EVENT_UNFILTERED arg2 UNIT_DIED, PLAYER_TARGET_CHANGED, LOOT_OPENED, (LOOT_CLOSED, [LOOT_SLOT_CLEARED, ITEM_PUSH, CHAT_MSG_LOOT]), PLAYER_TARGET_CHANGED, SPELLCAST_SENT, SPELLCAST_START, SUCCEEDED/INTERRUPTED, STOP, LOOT_OPENED (etc)
589 ITEM_PUSH can happen after LOOT_CLOSED, but it still happens.
590 Between LOOT_OPENED and LOOT_CLOSED, the lootable target is still targeted. Unsure what happens when looting items. LOOT_CLOSED triggers first if we target someone else.
591 ITEM_PUSH happens, then CHAT_MSG_LOOT. CHAT_MSG_LOOT includes quite a lot of potentially useful arguments.
592 PLAYER_TARGET_CHANGED before either looting or skinning.
593 SPELLCAST_SENT, SPELLCAST_START, SUCCEEDED/INTERRUPTED, STOP in that order. Arg4 on SENT seems to be the target's name. Arg4 on the others appears to be a unique identifier.
594 When started, we target the right thing. After that, we don't seem to. Check the combat log.