1 QuestHelper_File
["collect_loot.lua"] = "Development Version"
3 local debug_output
= false
4 if QuestHelper_File
["collect_loot.lua"] == "Development Version" then debug_output
= true end
18 local members_count
= 0
19 local members_refs
= {} -- "raid6" and the like
21 local function MembersUpdate()
22 -- 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.
28 --QuestHelper:TextOut("MU start")
29 members
= {} -- we burn a table every time this updates, but whatever
31 if GetNumRaidMembers() > 0 then
34 local ite
= string.format("raid%d", i
)
35 local gud
= UnitGUID(ite
)
38 table.insert(members_refs
, ite
)
39 --QuestHelper:TextOut(string.format("raid member %s added", UnitName(ite)))
42 elseif GetNumPartyMembers() > 0 then
45 local ite
= string.format("party%d", i
)
46 local gud
= UnitGUID(ite
)
49 table.insert(members_refs
, ite
)
50 --QuestHelper:TextOut(string.format("party member %s added", UnitName(ite)))
53 members
[UnitGUID("player")] = true
54 table.insert(members_refs
, "player")
55 --QuestHelper:TextOut(string.format("player %s added", UnitName("player")))
58 if UnitGUID("player") then members
[UnitGUID("player")] = true end -- it's possible that we haven't logged in entirely yet
59 table.insert(members_refs
, "player")
60 --QuestHelper:TextOut(string.format("player %s added as %s", UnitName("player"), tostring(UnitGUID("player"))))
64 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.
66 for _
, _
in pairs(members
) do members_count
= members_count
+ 1 end -- lulz
69 local MS_TAPPED_US
= 1
70 local MS_TAPPED_OTHER
= 2
71 local MS_TAPPED_LOOTABLE
= 3
72 local MS_TAPPED_LOOTED
= 4
74 local last_cleanup
= GetTime()
76 local monsterstate
= {}
77 local monsterrefresh
= {}
78 local monstertimeout
= {}
80 -- This all does something quite horrible.
81 -- 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.
82 -- 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.
83 -- 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.
84 -- 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".)
85 -- On top of this, we want to avoid looting "discarded items", but unfortunately there's no real good way to determine this. Welp.
86 local function CombatLogEvent(_
, event
, sourceguid
, _
, _
, destguid
, _
, _
, _
, spellname
)
87 -- There's many things that are handled here.
88 -- 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.
89 -- 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.
90 if event
~= "UNIT_DIED" then
91 -- Something has been attacked by something, maybe.
92 if not string.find(event
, "_DAMAGE$") then return end -- We only care about something punching something else.
95 if members
[sourceguid
] then target
= destguid
elseif members
[destguid
] then target
= sourceguid
end -- If one of the items is in our party, the other is our target.
96 if not target
then return end -- If we don't have a target, then nobody is in our party, and we don't care.
98 if monsterrefresh
[target
] and monsterrefresh
[target
] > GetTime() then return end -- we already have fresh data, so we're good
100 -- 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 their pets, and hope *someone* has it targeted. Luckily, we can stop once we find someone who does.
102 for _
, v
in pairs(members_refs
) do
103 targ
= v
.. "target" if UnitGUID(targ
) == target
then break end
104 targ
= v
.. "pettarget" if UnitGUID(targ
) == target
then break end
108 if not targ
then return end -- Well, nobody seems to be targeting it. That's . . . odd, and annoying. We'll take a look at it next combat message, I suppose.
110 -- Okay. So we know who's targeting it. Now, let's see who has it tapped, if anyone.
111 if not UnitIsTapped(targ
) then
112 -- Great. Nobody is. That is just *great*. Look how exuberant I feel at this moment.
113 monsterstate
[target
] = nil
114 monsterrefresh
[target
] = nil
115 monstertimeout
[target
] = nil
116 --QuestHelper:TextOut(string.format("Monster ignorified"))
118 -- We know someone is, so we're going to set up our caching . . .
119 monsterrefresh
[target
] = GetTime() + 15
120 monstertimeout
[target
] = GetTime() + 30
121 monsterstate
[target
] = (UnitIsTappedByPlayer(targ
) and not UnitIsTrivial(targ
)) and MS_TAPPED_US
or MS_TAPPED_OTHER
-- and figure out if it's us. Or if it's trivial. we ignore it if it's trivial, since it's much less likely to be looted and that could throw off our numbers
122 --QuestHelper:TextOut(string.format("Monster %s set to %s", target, (monsterstate[target] == MS_TAPPED_US) and "MS_TAPPED_US" or "MS_TAPPED_OTHER"))
127 -- It's dead. Hooray!
129 if monsterstate
[destguid
] and monstertimeout
[destguid
] > GetTime() and monsterstate
[destguid
] == MS_TAPPED_US
and members_count
> 0 then -- yaaay
130 local type = GetMonsterType(destguid
)
131 if not QHC
.monster
[type] then QHC
.monster
[type] = {} end
132 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.
134 monsterstate
[destguid
] = MS_TAPPED_LOOTABLE
135 monsterrefresh
[destguid
] = GetTime() + 600
136 monstertimeout
[destguid
] = GetTime() + 600
137 --QuestHelper:TextOut(string.format("Tapped monster %s slain, set to lootable", destguid))
139 monsterstate
[destguid
] = nil
140 monsterrefresh
[destguid
] = nil
141 monstertimeout
[destguid
] = nil
142 --QuestHelper:TextOut(string.format("Untapped monster %s slain, cleared", destguid))
149 skintypes
[UNIT_SKINNABLE_ROCK
] = "mine"
150 skintypes
[UNIT_SKINNABLE_HERB
] = "herb"
151 skintypes
[UNIT_SKINNABLE_BOLTS
] = "eng"
152 skintypes
[UNIT_SKINNABLE_LEATHER
] = "skin"
154 local function SkinnableflagsTooltipy(self
, ...)
155 --QuestHelper:TextOut("tooltipy")
156 if UnitExists("mouseover") and UnitIsVisible("mouseover") and not UnitIsPlayer("mouseover") and not UnitPlayerControlled("mouseover") and UnitIsDead("mouseover") then
157 local guid
= UnitGUID("mouseover")
158 --QuestHelper:TextOut("critar")
159 if not monsterstate
[guid
] or monsterstate
[guid
] ~= MS_TAPPED_LOOTED
or monsterrefresh
[guid
] > GetTime() then return end
160 --QuestHelper:TextOut("runin")
162 local cid
= GetMonsterType(guid
)
166 local lines
= GameTooltip
:NumLines()
168 --QuestHelper:TextOut(_G["GameTooltipTextLeft" .. tostring(i)]:GetText())
169 local skeen
= skintypes
[_G
["GameTooltipTextLeft" .. tostring(i
)]:GetText()]
170 if skeen
then QuestHelper
: Assert(not skintype
) skintype
= skeen
end
173 if not QHC
.monster
[cid
] then QHC
.monster
[cid
] = {} end
174 local qhci
= QHC
.monster
[cid
]
176 for _
, v
in pairs(skintypes
) do
177 if v
== skintype
then
178 --QuestHelper:TextOut(v .. "_yes")
179 qhci
[v
.. "_yes"] = (qhci
[v
.. "_yes"] or 0) + 1
181 --QuestHelper:TextOut(v .. "_no")
182 qhci
[v
.. "_no"] = (qhci
[v
.. "_no"] or 0) + 1
188 -- Logic behind this module:
189 -- Watch for the spell to be sent
190 -- Watch for it to start
191 -- Check out the combat log and see what GUID we get
192 -- If the GUID is null, we're targeting an object, otherwise, we're targeting a critter
193 -- Wait for spell to succeed
194 -- If anything doesn't synch up, or the spell is interrupted, nil out all these items.
195 -- We've got a little special case for pickpocketing, because people often use macros, so we detect that case specifically.
199 local PP_PHASE_COMPLETE
201 local pickpocket_phase
= PP_PHASE_IDLE
202 local pickpocket_target
203 local pickpocket_otarget_guid
204 local pickpocket_timestamp
206 local pickpocket_name
= GetSpellInfo(921) -- this is the pickpocket spell ID
208 local function pp_reset()
209 pickpocket_target
, pickpocket_otarget_guid
, pickpocket_timestamp
, pickpocket_phase
= nil, nil, nil, PP_PHASE_IDLE
213 local function PPSent(player
, spell
, _
, target
)
214 if player
~= "player" then return end
215 if spell
~= pickpocket_name
then return end
216 if UnitName("target") ~= target
then return end -- DENY
218 pickpocket_timestamp
, pickpocket_target
, pickpocket_otarget_guid
, pickpocket_phase
= GetTime(), target
, UnitGUID("target"), PP_PHASE_SENT
221 local function PPSucceed(player
, spell
, rank
)
222 if player
~= "player" then return end
223 if spell
~= pickpocket_name
then return end
225 if pickpocket_phase
~= PP_PHASE_SENT
and (not pickpocket_otarget_guid
or last_timestamp
+ 1 < GetTime()) then
230 pickpocket_timestamp
, pickpocket_phase
= GetTime(), PP_PHASE_COMPLETE
234 -- This segment deals with openable containers
237 local touched_timestamp
239 local function ItemLock(bag
, slot
)
240 if not bag
or not slot
then return end -- probably changing equipment
242 local _
, _
, locked
= GetContainerItemInfo(bag
, slot
)
243 --QuestHelper:TextOut(string.format("trying lock %s", tostring(locked)))
245 touched_itemid
= GetItemType(GetContainerItemLink(bag
, slot
))
246 --[[QuestHelper:TextOut(string.format("trying lock %s", tostring(touched_itemid)))
247 QuestHelper:TextOut(string.format("trying lock %s", tostring(type(touched_itemid))))
248 QuestHelper:TextOut(string.format("trying lock %s", tostring(QHC.item[touched_itemid].open_yes)))
249 QuestHelper:TextOut(string.format("trying lock %s", tostring(QHC.item[touched_itemid].open_no)))]]
250 touched_timestamp
= GetTime()
251 if not QHC
.item
[touched_itemid
] or (QHC
.item
[touched_itemid
].open_yes
or 0) <= (QHC
.item
[touched_itemid
].open_no
or 0) then
253 touched_timestamp
= nil
257 touched_timestamp
= nil
262 -- 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?)
264 local LAST_PHASE_IDLE
= 0
265 local LAST_PHASE_SENT
= 1
266 local LAST_PHASE_START
= 2
267 local LAST_PHASE_COMBATLOG
= 3
268 local LAST_PHASE_COMPLETE
= 4
270 local last_phase
= LAST_PHASE_IDLE
274 local last_target_guid
276 local last_otarget_guid
278 local last_succeed
= false
279 local last_succeed_trade
= GetTime()
281 local gathereffects
= {}
283 gathereffects
[GetSpellInfo(51306)] = {token
= "eng", noclog
= true}
284 gathereffects
[GetSpellInfo(32606)] = {token
= "mine"}
285 gathereffects
[GetSpellInfo(2366)] = {token
= "herb"}
286 gathereffects
[GetSpellInfo(8613)] = {token
= "skin"}
287 gathereffects
[GetSpellInfo(21248)] = {token
= "open", noclog
= true}
288 gathereffects
[GetSpellInfo(30427)] = {token
= "extract", noclog
= true} -- not a loot window, so it won't really work, but hey
289 gathereffects
[GetSpellInfo(13262)] = {token
= "de", noclog
= true, ignore
= true}
290 gathereffects
[GetSpellInfo(31252)] = {token
= "prospect", noclog
= true, ignore
= true}
291 gathereffects
[GetSpellInfo(51005)] = {token
= "mill", noclog
= true, ignore
= true}
295 local function last_reset()
296 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
300 -- This all doesn't work with instant spells. Luckily, I don't care about instant spells (yet).
301 local function SpellSent(player
, spell
, rank
, target
)
302 if player
~= "player" then return end
304 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
306 if last_otarget
and last_otarget
~= last_target
then last_reset() return end
308 --QuestHelper:TextOut(string.format("ss %s", spell))
311 local function SpellStart(player
, spell
, rank
)
312 if player
~= "player" then return end
314 if spell
~= last_spell
or rank
~= last_rank
or last_target_guid
or last_phase
~= LAST_PHASE_SENT
or last_timestamp
+ 1 < GetTime() then
317 --QuestHelper:TextOut(string.format("sst %s", spell))
318 last_timestamp
, last_phase
= GetTime(), LAST_PHASE_START
322 local function SpellCombatLog(_
, event
, sourceguid
, _
, _
, destguid
, _
, _
, _
, spellname
)
323 if event
~= "SPELL_CAST_START" then return end
325 if sourceguid
~= UnitGUID("player") then return end
327 --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())))
329 if spellname
~= last_spell
or not last_target
or last_target_guid
or last_timestamp
+ 1 < GetTime() then
334 --QuestHelper:TextOut("cle_ss enter")
336 if last_phase
~= LAST_PHASE_START
then
341 --QuestHelper:TextOut(string.format("cesst %s", spellname))
342 last_timestamp
, last_target_guid
, last_phase
= GetTime(), destguid
, LAST_PHASE_COMBATLOG
344 if last_target_guid
== "0x0000000000000000" then last_target_guid
= nil end
345 if last_target_guid
and last_target_guid
~= last_otarget_guid
then last_reset() return end
348 local function SpellSucceed(player
, spell
, rank
)
349 if player
~= "player" then return end
351 if gathereffects
[spell
] then last_succeed_trade
= GetTime() end
353 --QuestHelper:TextOut(string.format("sscu enter %s %s %s %s %s", tostring(last_spell), tostring(last_target), tostring(last_rank), tostring(spell), tostring(rank)))
355 if not last_spell
or not last_target
or last_spell
~= spell
or last_rank
~= rank
then
360 --QuestHelper:TextOut("sscu enter")
362 if gathereffects
[spell
] and gathereffects
[spell
].noclog
then
363 if last_phase
~= LAST_PHASE_START
or last_timestamp
+ 10 < GetTime() then
368 if last_phase
~= LAST_PHASE_COMBATLOG
or last_timestamp
+ 10 < GetTime() then
374 --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)))
375 last_timestamp
, last_succeed
, last_phase
= GetTime(), true, LAST_PHASE_COMPLETE
376 --QuestHelper:TextOut(string.format("last_phase %d", last_phase))
378 --[[if last_phase == LAST_PHASE_COMPLETE then
379 QuestHelper:TextOut(string.format("spell succeeded, casting %s %s on %s/%s", last_spell, last_rank, tostring(last_target), tostring(last_target_guid)))
383 local function SpellInterrupt(player
, spell
, rank
)
384 if player
~= "player" then return end
386 -- I don't care what they were casting, they're certainly not doing it now
387 --QuestHelper:TextOut(string.format("si %s", spell))
391 local function LootOpened()
393 -- We're cleaning up the monster charts here, on the theory that if someone is looting, they're okay with a tiny lag spike.
394 if last_cleanup
+ 300 < GetTime() then
396 for k
, v
in pairs(monstertimeout
) do
397 if v
< GetTime() then table.insert(cleanup
, k
) end
400 for _
, v
in pairs(cleanup
) do
401 monsterstate
[v
] = nil
402 monsterrefresh
[v
] = nil
403 monstertimeout
[v
] = nil
407 -- First off, we try to figure out where the hell these items came from.
409 --QuestHelper:TextOut(string.format("%s %s %s", tostring(last_phase == LAST_PHASE_COMPLETE), tostring(last_spell == "Mining"), tostring(last_timestamp + 1 > GetTime())))
410 --QuestHelper:TextOut(string.format("%s %s %s", tostring(last_phase == LAST_PHASE_COMPLETE), tostring(last_spell == "Mining"), tostring(last_timestamp + 1 > GetTime())))
412 --if last_timestamp then QuestHelper:TextOut(string.format("%s %s %s", tostring(last_phase == LAST_PHASE_COMPLETE), tostring(last_spell == "Mining"), tostring(last_timestamp + 1 > GetTime()))) else QuestHelper:TextOut("timmy") end
413 --if pickpocket_phase == PP_PHASE_COMPLETE then QuestHelper:TextOut(string.format("%s", tostring(pickpocket_timestamp))) else QuestHelper:TextOut("nein") end
415 --local beef = string.format("%s/%s %s/%s", tostring(last_target), tostring(last_target_guid), tostring(last_otarget), tostring(last_otarget_guid))
420 if IsFishingLoot() then
422 if debug_output
then QuestHelper
:TextOut("Fishing loot") end
424 if not QHC
.fishing
[loc
] then QHC
.fishing
[loc
] = {} end
425 spot
= QHC
.fishing
[loc
]
428 elseif pickpocket_phase
== PP_PHASE_COMPLETE
and pickpocket_timestamp
and pickpocket_timestamp
+ 1 > GetTime() and UnitGUID("target") == pickpocket_otarget_guid
then
429 if debug_output
then QuestHelper
:TextOut(string.format("Pickpocketing from %s/%s", pickpocket_target
, UnitName("target"), UnitGUID("target"))) end
430 local mid
= GetMonsterType(UnitGUID("target"))
431 if not QHC
.monster
[mid
] then QHC
.monster
[mid
] = {} end
432 spot
= QHC
.monster
[mid
]
435 elseif last_phase
== LAST_PHASE_COMPLETE
and gathereffects
[last_spell
] and last_timestamp
+ 1 > GetTime() then
436 local beef
= string.format("%s/%s %s/%s", tostring(last_target
), tostring(last_target_guid
), tostring(last_otarget
), tostring(last_otarget_guid
))
438 if gathereffects
[last_spell
].ignore
then return end
440 prefix
= gathereffects
[last_spell
].token
442 -- this one is sort of grim actually
443 -- If we have an last_otarget_guid, it's the right one, and it's a monster
444 -- If we don't, use last_target, and it's an object
445 -- This is probably going to be buggy. Welp.
446 if last_otarget_guid
then
447 if debug_output
then QuestHelper
:TextOut(string.format("%s from monster %s", gathereffects
[last_spell
].token
, beef
)) end
448 local mid
= GetMonsterType(last_otarget_guid
)
449 if not QHC
.monster
[mid
] then QHC
.monster
[mid
] = {} end
450 spot
= QHC
.monster
[mid
]
452 if debug_output
then QuestHelper
:TextOut(string.format("%s from object %s", gathereffects
[last_spell
].token
, beef
)) end
453 if not QHC
.object
[last_target
] then QHC
.object
[last_target
] = {} end
454 spot
= QHC
.object
[last_target
]
457 elseif touched_timestamp
and touched_timestamp
+ 1 > GetTime() then
458 -- Opening a container, possibly
459 if debug_output
then QuestHelper
:TextOut(string.format("Opening container %d", touched_itemid
)) end
460 if not QHC
.item
[touched_itemid
] then QHC
.item
[touched_itemid
] = {} end
461 spot
= QHC
.item
[touched_itemid
]
464 elseif UnitGUID("target") and monsterstate
[UnitGUID("target")] == MS_TAPPED_LOOTABLE
and monstertimeout
[UnitGUID("target")] > 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
465 -- Monster is lootable, so we loot the monster
466 if debug_output
then QuestHelper
:TextOut(string.format("Monsterloot from %s/%s", UnitName("target"), UnitGUID("target"))) end
467 monsterstate
[UnitGUID("target")] = MS_TAPPED_LOOTED
468 monstertimeout
[UnitGUID("target")] = GetTime() + 300
469 monsterrefresh
[UnitGUID("target")] = GetTime() + 2
470 local mid
= GetMonsterType(UnitGUID("target"))
471 if not QHC
.monster
[mid
] then QHC
.monster
[mid
] = {} end
472 spot
= QHC
.monster
[mid
]
476 if debug_output
then QuestHelper
:TextOut("Who knows") end -- ugh
478 if not QHC
.worldloot
[loc
] then QHC
.worldloot
[loc
] = {} end
479 spot
= QHC
.worldloot
[loc
]
488 for i
= 1, GetNumLootItems() do
489 _
, name
, quant
, _
= GetLootSlotInfo(i
)
490 link
= GetLootSlotLink(i
)
493 local _
, _
, amount
= string.find(name
, Patterns
.GOLD_AMOUNT
)
494 if amount
then items
.gold
= items
.gold
+ tonumber(amount
) * 10000 end
496 local _
, _
, amount
= string.find(name
, Patterns
.SILVER_AMOUNT
)
497 if amount
then items
.gold
= items
.gold
+ tonumber(amount
) * 100 end
499 local _
, _
, amount
= string.find(name
, Patterns
.COPPER_AMOUNT
)
500 if amount
then items
.gold
= items
.gold
+ tonumber(amount
) * 1 end
502 local itype
= GetItemType(link
)
503 items
[itype
] = (items
[itype
] or 0) + quant
507 spot
[prefix
.. "_count"] = (spot
[prefix
.. "_count"] or 0) + 1
508 if not spot
[prefix
.. "_loot"] then spot
[prefix
.. "_loot"] = {} end
509 local pt
= spot
[prefix
.. "_loot"]
510 for k
, v
in pairs(items
) do
511 if v
> 0 then pt
[k
] = (pt
[k
] or 0) + v
end
515 function QH_Collect_Loot_Init(QHCData
, API
)
518 if not QHC
.monster
then QHC
.monster
= {} end
519 if not QHC
.worldloot
then QHC
.worldloot
= {} end
520 if not QHC
.fishing
then QHC
.fishing
= {} end
521 if not QHC
.item
then QHC
.item
= {} end
523 API
.Registrar_EventHook("PLAYER_ENTERING_WORLD", MembersUpdate
)
524 API
.Registrar_EventHook("RAID_ROSTER_UPDATE", MembersUpdate
)
525 API
.Registrar_EventHook("PARTY_MEMBERS_CHANGED", MembersUpdate
)
526 API
.Registrar_EventHook("COMBAT_LOG_EVENT_UNFILTERED", CombatLogEvent
)
528 API
.Registrar_EventHook("UPDATE_MOUSEOVER_UNIT", SkinnableflagsTooltipy
)
530 API
.Registrar_EventHook("UNIT_SPELLCAST_SENT", PPSent
)
531 API
.Registrar_EventHook("UNIT_SPELLCAST_SUCCEEDED", PPSucceed
)
533 API
.Registrar_EventHook("ITEM_LOCK_CHANGED", ItemLock
)
535 API
.Registrar_EventHook("UNIT_SPELLCAST_SENT", SpellSent
)
536 API
.Registrar_EventHook("UNIT_SPELLCAST_START", SpellStart
)
537 API
.Registrar_EventHook("COMBAT_LOG_EVENT_UNFILTERED", SpellCombatLog
)
538 API
.Registrar_EventHook("UNIT_SPELLCAST_SUCCEEDED", SpellSucceed
)
539 API
.Registrar_EventHook("UNIT_SPELLCAST_INTERRUPTED", SpellInterrupt
)
541 API
.Registrar_EventHook("LOOT_OPENED", LootOpened
)
543 MembersUpdate() -- to get self, probably won't work but hey
545 GetMonsterUID
= API
.Utility_GetMonsterUID
546 GetMonsterType
= API
.Utility_GetMonsterType
547 GetItemType
= API
.Utility_GetItemType
548 QuestHelper
: Assert(GetMonsterUID
)
549 QuestHelper
: Assert(GetMonsterType
)
550 QuestHelper
: Assert(GetItemType
)
552 Patterns
= API
.Patterns
553 API
.Patterns_RegisterNumber("GOLD_AMOUNT")
554 API
.Patterns_RegisterNumber("SILVER_AMOUNT")
555 API
.Patterns_RegisterNumber("COPPER_AMOUNT")
557 GetLoc
= API
.Callback_LocationBolusCurrent
558 QuestHelper
: Assert(GetLoc
)
560 -- What I want to know is whether it was tagged by me or my group when dead
561 -- Check target-of-each-groupmember? Once we see him tapped once, and by us, it's probably sufficient.
565 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)
567 ITEM_PUSH can happen after LOOT_CLOSED, but it still happens.
568 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.
569 ITEM_PUSH happens, then CHAT_MSG_LOOT. CHAT_MSG_LOOT includes quite a lot of potentially useful arguments.
570 PLAYER_TARGET_CHANGED before either looting or skinning.
571 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.
572 When started, we target the right thing. After that, we don't seem to. Check the combat log.