tl;dr - For UI_ERROR_MESSAGE, it is not GUID specific. Here is what I made.
Code:
-- make tables
if not LosTable then LosTable = {} end;
if not BehindTargetTable then BehindTargetTable = {} end;
if not TargetFacingTable then TargetFacingTable = {} end;
if not FacingTargetTable then FacingTargetTable = {} end;
function SpellCastFailed(targetCheck,failCheck,timeCheck)
local timeCheck = timeCheck or 0.7
local destGUID = UnitGUID(targetCheck) or 0 -- this probably needs to be fail specific and globalized
local failCheck = failCheck or "all"
-- table cleaning needs to be failType and GUID specific
if failCheck == "LineOfSight" or failCheck == "IsLineOfSight" or failCheck == "all" then
if LosTable[destGUID] and timeCheck < (GetTime() - LosTable[destGUID].time) then
LosTable[destGUID] = nil
end
end
if failCheck == "BehindTarget" or failCheck == "IsBehindTarget" or failCheck == "all" then
if BehindTargetTable[destGUID] and timeCheck < (GetTime() - BehindTargetTable[destGUID].time) then
BehindTargetTable[destGUID] = nil
end
end
if failCheck == "TargetFacing" or failCheck == "TargetIsFacing" or failCheck == "all" then
if TargetFacingTable[destGUID] and timeCheck < (GetTime() - TargetFacingTable[destGUID].time) then
TargetFacingTable[destGUID] = nil
end
end
if failCheck == "FacingTarget" or failCheck == "IsFacingTarget" or failCheck == "all" then
if FacingTargetTable[destGUID] and timeCheck < (GetTime() - FacingTargetTable[destGUID].time) then
FacingTargetTable[destGUID] = nil
end
end
-- once the GUID is in the table, set globabl GUID to nil and unregister all events
local function SpellFailed_OnEvent(self, event, ...)
local timestamp, type, _, sourceGUID, sourceName, sourceFlags, _, _, destName, destFlags, _ = ...;
local playerGUID = UnitGUID("player")
local destGUID = UnitGUID(targetCheck) or 0
local failCheck = failCheck or "all"
if event == "COMBAT_LOG_EVENT_UNFILTERED" then
if type == "SPELL_CAST_FAILED" then
if sourceGUID == playerGUID then
local failType = select(15,...)
if failCheck == "LineOfSight" or failCheck == "IsLineOfSight" or failCheck == "all" then
if (failType == SPELL_FAILED_LINE_OF_SIGHT or failType == "Target not in line of sight") then
if not LosTable[destGUID] then
LosTable[destGUID] = {time = GetTime()}
SpellFailed:UnregisterAllEvents()
return
end
end
elseif failCheck == "BehindTarget" or failCheck == "IsBehindTarget" or failCheck == "all" then
if (failType == SPELL_FAILED_NOT_BEHIND or failType == "You must be behind your target.") then
if not BehindTargetTable[destGUID] then
BehindTargetTable[destGUID] = {time = GetTime()}
SpellFailed:UnregisterAllEvents()
return
end
end
elseif failCheck == "TargetFacing" or failCheck == "TargetIsFacing" or failCheck == "all" then
if (failType == SPELL_FAILED_NOT_INFRONT or failType == "You must be in front of your target.") then
if not TargetFacingTable[destGUID] then
TargetFacingTable[destGUID] = {time = GetTime()}
SpellFailed:UnregisterAllEvents()
return
end
end
elseif failCheck == "FacingTarget" or failCheck == "IsFacingTarget" or failCheck == "all" then
if (failType == SPELL_FAILED_UNIT_NOT_INFRONT or failType == "Target needs to be in front of you.") then
if not FacingTargetTable[destGUID] then
FacingTargetTable[destGUID] = {time = GetTime()}
SpellFailed:UnregisterAllEvents()
return
end
end
end
end
end
end
if event == "UI_ERROR_MESSAGE" then
local Message = ...
if (Message == SPELL_FAILED_LINE_OF_SIGHT or Message == "Target not in line of sight") then
if not LosTable[destGUID] then
LosTable[destGUID] = {time = GetTime()}
SpellFailed:UnregisterAllEvents()
return
end
end
if (Message == SPELL_FAILED_NOT_BEHIND or Message == "You must be behind your target.") then
if not BehindTargetTable[destGUID] then
BehindTargetTable[destGUID] = {time = GetTime()}
SpellFailed:UnregisterAllEvents()
return
end
end
if (Message == SPELL_FAILED_NOT_INFRONT or Message == "You must be in front of your target.") then
if not TargetFacingTable[destGUID] then
TargetFacingTable[destGUID] = {time = GetTime()}
SpellFailed:UnregisterAllEvents()
return
end
end
if (Message == SPELL_FAILED_UNIT_NOT_INFRONT or Message == "Target needs to be in front of you.") then
if not FacingTargetTable[destGUID] then
FacingTargetTable[destGUID] = {time = GetTime()}
SpellFailed:UnregisterAllEvents()
return
end
end
end
end
-- if in table, return false
if failCheck == "LineOfSight" or failCheck == "IsLineOfSight" or failCheck == "all" then
if LosTable[destGUID] then
return false
end
end
if failCheck == "BehindTarget" or failCheck == "IsBehindTarget" or failCheck == "all" then
if BehindTargetTable[destGUID] then
return false
end
end
if failCheck == "TargetFacing" or failCheck == "TargetIsFacing" or failCheck == "all" then
if TargetFacingTable[destGUID] then
return false
end
end
if failCheck == "FacingTarget" or failCheck == "IsFacingTarget" or failCheck == "all" then
if FacingTargetTable[destGUID] then
return false
end
end
-- make frame, set script
if not SpellFailed then
SpellFailed = CreateFrame("frame","spellFailedFrame")
SpellFailed:Hide()
SpellFailed:SetScript("OnEvent",SpellFailed_OnEvent)
end
-- this causes FPS issues after every true value, needs to be fixed.
SpellFailed:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
SpellFailed:RegisterEvent("UI_ERROR_MESSAGE")
return true
end
This function includes if you are facing target, if the target is facing you, if you're behind target, and if you're out of line of sight.
I forgot to mention, this fucntion only works for cata+. You need to modify
Code:
local timestamp, type, _, sourceGUID, sourceName, sourceFlags, _, _, destName, destFlags, _ = ...;
to
Code:
local timestamp, type, sourceGUID, sourceName, sourceFlags, _, destName, destFlags, = ...;
and change
Code:
local failType = select(15,...)
to
Code:
local failType = select(12,...)
because 3 variables have been added in cata 4.1 and 4.2. We shift it 3 placements backwards.