Vampify v0.4.0
This commit is contained in:
@@ -117,6 +117,42 @@ function G.onDamage(fn) table.insert(listeners, fn) end
|
||||
local goSeen = false
|
||||
local damageSeen = false
|
||||
|
||||
-- ---- "did the PLAYER cast this, or did it proc?" (per-hit export field `cast`) ----------------
|
||||
--
|
||||
-- The same SPELL_GO_SELF that latches goSeen above is also the only observable in the client that
|
||||
-- separates a CAST spell from a PROCCED one: it precedes the damage events of a cast and never
|
||||
-- fires for an item/enchant proc (the sentence right above G.deriveAoE says exactly this, and it
|
||||
-- is why deriveAoE had to exist at all). Hypothesis H2 -- that Vampirism is gated on the TRIGGER
|
||||
-- PATH ("was this triggered by an aura") rather than on "is this an item proc" -- turns on that
|
||||
-- distinction for one and the same spell id, so the offline analysis needs it recorded per hit
|
||||
-- rather than inferred from timing (see core/perhit.lua's formatHitLine comment).
|
||||
--
|
||||
-- Keyed by spell id, and deliberately WITHOUT the eviction sweep this project requires of
|
||||
-- per-GUID tables: the key space here is the player's own castable spell ids, which is bounded by
|
||||
-- the spellbook and does not grow with time or with mob spawns. That is the exact property the
|
||||
-- eviction rule exists to protect against, and it does not apply.
|
||||
local lastGo = {}
|
||||
|
||||
-- Pure, so the predicate is testable without firing events: "was there a cast of this spell id
|
||||
-- within `window` seconds before `now`". Default window 1.5s -- comfortably longer than the gap
|
||||
-- between SPELL_GO_SELF and the damage events of the same cast (the GO precedes them within the
|
||||
-- same or the next frame), and short enough that the PREVIOUS cast of the same spell (global
|
||||
-- cooldown 1.5s at the very fastest) cannot be mistaken for this one.
|
||||
local CAST_WINDOW = 1.5
|
||||
G.CAST_WINDOW = CAST_WINDOW
|
||||
|
||||
function G.noteCast(spellId, t)
|
||||
if spellId then lastGo[spellId] = t end
|
||||
end
|
||||
|
||||
function G.castSeenFor(spellId, now, window)
|
||||
if not spellId then return false end
|
||||
local t = lastGo[spellId]
|
||||
if not t or not now then return false end
|
||||
local dt = now - t
|
||||
return dt >= 0 and dt <= (window or CAST_WINDOW)
|
||||
end
|
||||
|
||||
-- ---- AoE derivation from distinct targets, cast or not (spec 4.2, extended 2026-08-22) --------
|
||||
--
|
||||
-- Originally written as the fallback for weapon/item procs (Force Reactive Disc's damage shield
|
||||
@@ -248,6 +284,10 @@ if CreateFrame then
|
||||
-- actual decision for every hit of this cast still runs through G.deriveAoE below, the
|
||||
-- exact same distinct-target proof a no-cast proc already has to provide.
|
||||
goSeen = true
|
||||
-- arg2 is the cast's spell id (see the event's field list at the top of this file).
|
||||
-- Noting it is what lets a later damage event of the SAME id say "this one was cast",
|
||||
-- which is the `cast` field of the per-hit export -- see G.castSeenFor above.
|
||||
G.noteCast(arg2, GetTime())
|
||||
elseif event == "SPELL_DAMAGE_EVENT_SELF" then
|
||||
local amount, tgt, spellId, caster = G.decodeSpell(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
|
||||
-- Trust arg2 rather than the _SELF suffix, and never count a hit on ourselves.
|
||||
|
||||
Reference in New Issue
Block a user