1939 lines
66 KiB
Lua
1939 lines
66 KiB
Lua
--[[ BuffTrigger.lua
|
|
This file contains the "aura" trigger for buffs and debuffs.
|
|
|
|
It registers the BuffTrigger table for the trigger type "aura" and has the following API:
|
|
|
|
Add(data)
|
|
Adds an aura, setting up internal data structures for all buff triggers.
|
|
|
|
LoadDisplays(id)
|
|
Loads the aura ids, enabling all buff triggers in the aura.
|
|
|
|
UnloadDisplays(id)
|
|
Unloads the aura ids, disabling all buff triggers in the aura.
|
|
|
|
UnloadAll()
|
|
Unloads all auras, disabling all buff triggers.
|
|
|
|
ScanAll()
|
|
Updates all triggers by checking all triggers.
|
|
|
|
Delete(id)
|
|
Removes all data for aura id.
|
|
|
|
Rename(oldid, newid)
|
|
Updates all data for aura oldid to use newid.
|
|
|
|
Modernize(data)
|
|
Updates all buff triggers in data.
|
|
|
|
#####################################################
|
|
# Helper functions mainly for the WeakAuras Options #
|
|
#####################################################
|
|
|
|
CanHaveDuration(data, triggernum)
|
|
Returns whether the trigger can have a duration.
|
|
|
|
GetOverlayInfo(data, triggernum)
|
|
Returns a table containing all overlays. Currently there aren't any
|
|
|
|
CanHaveAuto(data, triggernum)
|
|
Returns whether the icon can be automatically selected.
|
|
|
|
CanHaveClones(data, triggernum)
|
|
Returns whether the trigger can have clones.
|
|
|
|
CanHaveTooltip(data, triggernum)
|
|
Returns the type of tooltip to show for the trigger.
|
|
|
|
GetNameAndIcon(data, triggernum)
|
|
Returns the name and icon to show in the options.
|
|
|
|
GetAdditionalProperties(data, triggernum)
|
|
Returns the tooltip text for additional properties.
|
|
|
|
GetTriggerConditions(data, triggernum)
|
|
Returns the potential conditions for a trigger
|
|
]]--
|
|
|
|
if not WeakAuras.IsCorrectVersion() then return end
|
|
|
|
-- Lua APIs
|
|
local tinsert, wipe = table.insert, wipe
|
|
local pairs, next, type = pairs, next, type
|
|
local BUFF_MAX_DISPLAY = 255 -- Do tell when you find the real value.
|
|
local UnitGroupRolesAssigned = function() return "DAMAGER" end
|
|
|
|
local WeakAuras = WeakAuras;
|
|
local L = WeakAuras.L;
|
|
local BuffTrigger = {};
|
|
|
|
local timer = WeakAuras.timer;
|
|
local function_strings = WeakAuras.function_strings;
|
|
local auras = WeakAuras.auras;
|
|
local specificBosses = WeakAuras.specificBosses;
|
|
local specificUnits = WeakAuras.specificUnits;
|
|
local loaded_auras = WeakAuras.loaded_auras;
|
|
|
|
WeakAuras.me = GetUnitName("player", true)
|
|
WeakAuras.myGUID = nil
|
|
|
|
local aura_cache = {};
|
|
do
|
|
aura_cache.max = 0;
|
|
aura_cache.watched = {};
|
|
aura_cache.players = {};
|
|
aura_cache.TANK = 0;
|
|
aura_cache.HEALER = 0;
|
|
aura_cache.DAMAGER = 0;
|
|
aura_cache.playerRole = "NONE";
|
|
|
|
--- Tests if aura_cache data is consistent with trigger settings, eg. OwnOnly, RemainingTime, StackCount.
|
|
-- Extra check needed because aura_cache can potentially contain data of two different triggers with different settings!
|
|
-- @param acEntry
|
|
-- @param data
|
|
-- @return boolean
|
|
local function TestNonUniformSettings(acEntry, data)
|
|
if(data.remFunc) then
|
|
if not(data.remFunc(acEntry.expirationTime - GetTime())) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- Test OwnOnly
|
|
if (
|
|
data.ownOnly == true and WeakAuras.myGUID ~= acEntry.casterGUID or
|
|
data.ownOnly == false and WeakAuras.myGUID == acEntry.casterGUID
|
|
) then
|
|
return false;
|
|
end
|
|
|
|
-- Test StackCount
|
|
if (data.count and not data.count(acEntry.count)) then
|
|
return false;
|
|
end
|
|
|
|
-- Success
|
|
return true;
|
|
end
|
|
|
|
function aura_cache.ForceUpdate()
|
|
if not(WeakAuras.IsPaused()) then
|
|
WeakAuras.ScanAurasGroup()
|
|
end
|
|
end
|
|
|
|
function aura_cache.Watch(self, id, triggernum)
|
|
self.watched[id] = self.watched[id] or {};
|
|
self.watched[id][triggernum] = self.watched[id][triggernum] or {};
|
|
self.watched[id][triggernum].players = self.watched[id][triggernum].players or {};
|
|
self:ForceUpdate()
|
|
end
|
|
|
|
function aura_cache.Rename(self, oldid, newid)
|
|
self.watched[newid] = self.watched[oldid];
|
|
self.watched[oldid] = nil;
|
|
end
|
|
|
|
function aura_cache.Unwatch(self, id, triggernum)
|
|
self.watched[id][triggernum] = nil;
|
|
end
|
|
|
|
function aura_cache.GetMaxNumber(self)
|
|
return self.max;
|
|
end
|
|
|
|
function aura_cache.GetNumber(self, id, triggernum, data)
|
|
local num = 0;
|
|
for guid, _ in pairs(self.players) do
|
|
-- Need to check if cached data conforms to trigger
|
|
if(self.watched[id][triggernum].players[guid] and TestNonUniformSettings(self.watched[id][triggernum].players[guid], data)) then
|
|
num = num + 1;
|
|
end
|
|
end
|
|
return num;
|
|
end
|
|
|
|
function aura_cache.GetDynamicInfo(self, id, triggernum, data)
|
|
local bestDuration, bestExpirationTime, bestName, bestIcon, bestCount, bestSpellId, bestUnitCaster = 0, math.huge, "", "", 0, 0, "";
|
|
if(self.watched[id] and self.watched[id][triggernum]) then
|
|
for guid, durationInfo in pairs(self.watched[id][triggernum].players) do
|
|
-- Need to check if cached data conforms to trigger
|
|
if(durationInfo.expirationTime < bestExpirationTime and TestNonUniformSettings(durationInfo, data)) then
|
|
bestDuration = durationInfo.duration;
|
|
bestExpirationTime = durationInfo.expirationTime;
|
|
bestName = durationInfo.name;
|
|
bestIcon = durationInfo.icon;
|
|
bestCount = durationInfo.count;
|
|
bestSpellId = durationInfo.spellId;
|
|
bestUnitCaster = durationInfo.unitCaster;
|
|
end
|
|
end
|
|
end
|
|
return bestDuration, bestExpirationTime, bestName, bestIcon, bestCount, bestSpellId, bestUnitCaster;
|
|
end
|
|
|
|
function aura_cache.GetPlayerDynamicInfo(self, id, triggernum, guid, data)
|
|
local bestDuration, bestExpirationTime, bestName, bestIcon, bestCount, bestSpellId, bestUnitCaster = 0, math.huge, "", "", 0, 0, "";
|
|
if(self.watched[id] and self.watched[id][triggernum]) then
|
|
local durationInfo = self.watched[id][triggernum].players[guid]
|
|
if(durationInfo) then
|
|
-- Need to check if cached data conforms to trigger
|
|
if(durationInfo.expirationTime < bestExpirationTime and TestNonUniformSettings(durationInfo, data)) then
|
|
bestDuration = durationInfo.duration;
|
|
bestExpirationTime = durationInfo.expirationTime;
|
|
bestName = durationInfo.name;
|
|
bestIcon = durationInfo.icon;
|
|
bestCount = durationInfo.count;
|
|
bestSpellId = durationInfo.spellId;
|
|
bestUnitCaster = durationInfo.unitCaster;
|
|
end
|
|
end
|
|
end
|
|
return bestDuration, bestExpirationTime, bestName, bestIcon, bestCount, bestSpellId, bestUnitCaster;
|
|
end
|
|
|
|
function aura_cache.GetAffected(self, id, triggernum, data)
|
|
local affected = {};
|
|
if(self.watched[id] and self.watched[id][triggernum]) then
|
|
for guid, acEntry in pairs(self.watched[id][triggernum].players) do
|
|
-- Need to check if cached data conforms to trigger
|
|
if (TestNonUniformSettings(acEntry, data)) then
|
|
affected[self.players[guid]] = true;
|
|
end
|
|
end
|
|
end
|
|
return affected;
|
|
end
|
|
|
|
function aura_cache.GetUnaffected(self, id, triggernum, data)
|
|
local affected = self:GetAffected(id, triggernum, data);
|
|
local ret = {};
|
|
for guid, name in pairs(self.players) do
|
|
if not(affected[name]) then
|
|
ret[name] = true;
|
|
end
|
|
end
|
|
return ret;
|
|
end
|
|
|
|
function aura_cache.AssertAura(self, id, triggernum, guid, duration, expirationTime, name, icon, count, casterGUID, spellId, unitCaster)
|
|
-- Don't watch aura on non watched players
|
|
if not self.players[guid] then return end
|
|
|
|
if not(self.watched[id][triggernum].players[guid]) then
|
|
self.watched[id][triggernum].players[guid] = {
|
|
duration = duration,
|
|
expirationTime = expirationTime,
|
|
name = name,
|
|
icon = icon,
|
|
count = count,
|
|
unitCaster = unitCaster,
|
|
spellId = spellId,
|
|
casterGUID = casterGUID
|
|
};
|
|
else
|
|
local auradata = self.watched[id][triggernum].players[guid];
|
|
if(expirationTime ~= auradata.expirationTime) then
|
|
auradata.duration = duration;
|
|
auradata.expirationTime = expirationTime;
|
|
auradata.name = name;
|
|
auradata.icon = icon;
|
|
auradata.count = count;
|
|
auradata.unitCaster = unitCaster;
|
|
auradata.spellId = spellId;
|
|
auradata.casterGUID = casterGUID;
|
|
end
|
|
end
|
|
end
|
|
|
|
function aura_cache.DeassertAura(self, id, triggernum, guid)
|
|
if(self.watched[id] and self.watched[id][triggernum] and self.watched[id][triggernum].players[guid]) then
|
|
self.watched[id][triggernum].players[guid] = nil;
|
|
end
|
|
end
|
|
|
|
function aura_cache.AssertMember(self, guid, name)
|
|
if not(self.players[guid]) then
|
|
self.max = self.max + 1;
|
|
end
|
|
self.players[guid] = name;
|
|
end
|
|
|
|
function aura_cache.DeassertMember(self, guid)
|
|
if(self.players[guid]) then
|
|
self.players[guid] = nil;
|
|
for id, v in pairs(self.watched) do
|
|
for triggernum, _ in pairs(v) do
|
|
self:DeassertAura(id, triggernum, guid);
|
|
end
|
|
end
|
|
self.max = self.max - 1;
|
|
end
|
|
end
|
|
|
|
function aura_cache.AssertMemberList(self, guids)
|
|
local toDelete = {};
|
|
|
|
for guid, _ in pairs(self.players) do
|
|
if not(guids[guid]) then
|
|
toDelete[guid] = true;
|
|
end
|
|
end
|
|
|
|
for guid, _ in pairs(toDelete) do
|
|
self:DeassertMember(guid);
|
|
end
|
|
for guid, name in pairs(guids) do
|
|
self:AssertMember(guid, name);
|
|
end
|
|
self:ForceUpdate();
|
|
end
|
|
end
|
|
WeakAuras.aura_cache = aura_cache;
|
|
|
|
function WeakAuras.SetAuraVisibility(id, triggernum, cloneId, buffShowOn, unitExists, active, unit, duration, expirationTime, name, icon, count, index, spellId, unitCaster)
|
|
local triggerState = WeakAuras.GetTriggerStateForTrigger(id, triggernum);
|
|
|
|
local show;
|
|
if (not UnitExists(unit)) then
|
|
show = unitExists;
|
|
elseif (buffShowOn == "showAlways") then
|
|
show = true;
|
|
elseif(buffShowOn == "showOnMissing") then
|
|
show = not active;
|
|
else
|
|
show = active;
|
|
end
|
|
|
|
cloneId = cloneId or "";
|
|
|
|
if (not show and not triggerState[cloneId]) then
|
|
return false;
|
|
end
|
|
|
|
triggerState[cloneId] = triggerState[cloneId] or {};
|
|
local state = triggerState[cloneId];
|
|
if (state.show ~= show) then
|
|
state.show = show;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.show) then
|
|
if (state.active ~= active) then
|
|
state.active = active;
|
|
state.changed = true;
|
|
end
|
|
if (state.index ~= index) then
|
|
state.index = index;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.spellId ~= spellId) then
|
|
state.spellId = spellId;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.progressType ~= "timed") then
|
|
state.progressType = "timed";
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.expirationTime ~= expirationTime) then
|
|
state.expirationTime = expirationTime;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.duration ~= duration) then
|
|
state.duration = duration;
|
|
state.changed = true;
|
|
end
|
|
|
|
local autoHide = false;
|
|
if (state.autoHide ~= autoHide) then
|
|
state.autoHide = autoHide;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.name ~= name) then
|
|
state.name = name;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.icon ~= icon) then
|
|
state.icon = icon;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.stacks ~= count) then
|
|
state.stacks = count;
|
|
state.changed = true;
|
|
end
|
|
|
|
unitCaster = unitCaster and UnitName(unitCaster);
|
|
if (state.unitCaster ~= unitCaster) then
|
|
state.unitCaster = unitCaster;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.GUID ~= UnitGUID(unit)) then
|
|
state.GUID = UnitGUID(unit);
|
|
state.changed = true;
|
|
end
|
|
end
|
|
|
|
if (state.changed) then
|
|
return true;
|
|
end
|
|
return false;
|
|
end
|
|
|
|
--- Calls GetSpellInfo on trigger data to return aura name and icon.
|
|
-- @param trigger
|
|
-- @return name and icon
|
|
local function GetNameAndIconFromTrigger(trigger)
|
|
if (trigger.fullscan) then
|
|
if (trigger.spellId) then
|
|
local name, _, icon = GetSpellInfo(trigger.spellId);
|
|
return name, icon;
|
|
end
|
|
if (trigger.name) then
|
|
return trigger.name, WeakAuras.GetDynamicIconCache(trigger.name);
|
|
end
|
|
else
|
|
if (trigger.spellIds and trigger.spellIds[1]) then
|
|
local name, _, icon = GetSpellInfo(trigger.spellIds[1]);
|
|
return name, icon;
|
|
end
|
|
if (trigger.names and trigger.names[1]) then
|
|
return trigger.names[1], WeakAuras.GetDynamicIconCache(trigger.names[1]);
|
|
end
|
|
end
|
|
end
|
|
|
|
local aura_scan_cache = {};
|
|
local aura_lists = {};
|
|
function WeakAuras.ScanAuras(unit)
|
|
local time = GetTime();
|
|
|
|
-- Reset scan cache for this unit
|
|
aura_scan_cache[unit] = aura_scan_cache[unit] or {};
|
|
for i,v in pairs(aura_scan_cache[unit]) do
|
|
v.up_to_date = 0;
|
|
end
|
|
|
|
-- Make unit available outside
|
|
local old_unit = WeakAuras.CurrentUnit;
|
|
WeakAuras.CurrentUnit = unit;
|
|
|
|
local fixedUnit = unit == "party0" and "player" or unit
|
|
local uGUID = UnitGUID(fixedUnit) or fixedUnit;
|
|
|
|
-- Link corresponding display (and aura cache)
|
|
local aura_object;
|
|
wipe(aura_lists);
|
|
if(unit:sub(1, 4) == "raid") then
|
|
if(aura_cache.players[uGUID]) then
|
|
aura_lists[1] = loaded_auras["group"];
|
|
aura_object = aura_cache;
|
|
end
|
|
elseif(unit:sub(1, 5) == "party") then
|
|
aura_lists[1] = loaded_auras["group"];
|
|
aura_object = aura_cache;
|
|
elseif(specificBosses[unit]) then
|
|
aura_lists[1] = loaded_auras["boss"];
|
|
elseif(unit:sub(1,5) == "arena") then
|
|
aura_lists[1] = loaded_auras["arena"];
|
|
else
|
|
if(unit == "player" and loaded_auras["group"]) then
|
|
WeakAuras.ScanAuras("party0");
|
|
end
|
|
aura_lists[1] = loaded_auras[unit];
|
|
end
|
|
|
|
-- Add group auras for specific units -- XXX: why?
|
|
if(specificUnits[unit] and not aura_object) then
|
|
tinsert(aura_lists, loaded_auras["group"]);
|
|
end
|
|
|
|
-- Locals
|
|
local cloneIdList;
|
|
local groupcloneToUpdate;
|
|
|
|
-- Units GUID
|
|
unit = fixedUnit;
|
|
|
|
-- Iterate over all displays (list of display lists)
|
|
for _, aura_list in pairs(aura_lists) do
|
|
-- Locals
|
|
local name, rank, icon, count, duration, expirationTime, unitCaster, isStealable, spellId = true;
|
|
local tooltip, debuffClass, tooltipSize;
|
|
local remaining, checkPassed;
|
|
|
|
-- Iterate over all displays (display lists)
|
|
for id,triggers in pairs(aura_list) do
|
|
WeakAuras.StartProfileAura(id);
|
|
-- Iterate over all triggers
|
|
local updateTriggerState = false;
|
|
for triggernum, data in pairs(triggers) do
|
|
if(not data.specificUnit or UnitIsUnit(data.unit, unit)) then
|
|
-- Filters
|
|
local filter = data.debuffType..(data.ownOnly and "|PLAYER" or "");
|
|
local active = false;
|
|
|
|
-- Full aura scan works differently
|
|
if(data.fullscan) then
|
|
-- Make sure scan cache exists
|
|
aura_scan_cache[unit][filter] = aura_scan_cache[unit][filter] or {up_to_date = 0};
|
|
|
|
-- Reset clone list
|
|
if cloneIdList then wipe(cloneIdList); end
|
|
if(data.autoclone and not cloneIdList) then
|
|
cloneIdList = {};
|
|
end
|
|
|
|
-- Iterate over all units auras
|
|
local index = 0; name = true;
|
|
while(name) do
|
|
-- Get nexted!
|
|
index = index + 1;
|
|
|
|
-- Update scan cache
|
|
if(aura_scan_cache[unit][filter].up_to_date < index) then
|
|
-- Query aura data
|
|
name, rank, icon, count, debuffClass, duration, expirationTime, unitCaster, isStealable, _, spellId = UnitAura(unit, index, filter);
|
|
if (debuffClass == nil) then
|
|
debuffClass = "none";
|
|
elseif (debuffClass == "") then
|
|
debuffClass = "enrage"
|
|
else
|
|
debuffClass = string.lower(debuffClass);
|
|
end
|
|
local tooltipSize1, tooltipSize2, tooltipSize3;
|
|
tooltip, _, tooltipSize1, tooltipSize2, tooltipSize3 = WeakAuras.GetAuraTooltipInfo(unit, index, filter);
|
|
tooltipSize = {tooltipSize1, tooltipSize2, tooltipSize3}
|
|
aura_scan_cache[unit][filter][index] = aura_scan_cache[unit][filter][index] or {};
|
|
|
|
-- Save aura data to cache
|
|
local current_aura = aura_scan_cache[unit][filter][index];
|
|
current_aura.name = name;
|
|
current_aura.icon = icon;
|
|
current_aura.count = count;
|
|
current_aura.duration = duration;
|
|
current_aura.expirationTime = expirationTime;
|
|
current_aura.isStealable = isStealable;
|
|
current_aura.spellId = spellId;
|
|
current_aura.tooltip = tooltip;
|
|
current_aura.debuffClass = debuffClass;
|
|
current_aura.tooltipSize = tooltipSize;
|
|
current_aura.unitCaster = unitCaster;
|
|
|
|
-- Updated
|
|
aura_scan_cache[unit][filter].up_to_date = index;
|
|
|
|
-- Use cached data instead
|
|
else
|
|
-- Fetch cached aura data
|
|
local current_aura = aura_scan_cache[unit][filter][index];
|
|
name = current_aura.name;
|
|
icon = current_aura.icon;
|
|
count = current_aura.count;
|
|
duration = current_aura.duration;
|
|
expirationTime = current_aura.expirationTime;
|
|
isStealable = current_aura.isStealable;
|
|
spellId = current_aura.spellId;
|
|
tooltip = current_aura.tooltip;
|
|
debuffClass = current_aura.debuffClass;
|
|
tooltipSize = current_aura.tooltipSize;
|
|
if unitCaster ~= nil then
|
|
unitCaster = current_aura.unitCaster
|
|
else
|
|
unitCaster = "Unknown"
|
|
end
|
|
end
|
|
|
|
local casGUID = unitCaster and UnitGUID(unitCaster);
|
|
|
|
-- Aura conforms to trigger options?
|
|
if(data.subcount) then
|
|
local index = data.subcountCount or 1;
|
|
count = tooltipSize[index];
|
|
end
|
|
if(name and ((not data.count) or count and data.count(count)) and (data.ownOnly ~= false or not UnitIsUnit("player", unitCaster or "")) and data.scanFunc(name, tooltip, isStealable, spellId, debuffClass)) then
|
|
remaining = expirationTime - time;
|
|
checkPassed = true;
|
|
if(data.remFunc) then
|
|
if not(data.remFunc(remaining)) then
|
|
checkPassed = false;
|
|
end
|
|
|
|
-- Schedule remaining time, re-scan later
|
|
if(remaining > data.rem) then
|
|
WeakAuras.ScheduleAuraScan(unit, time + (remaining - data.rem));
|
|
end
|
|
end
|
|
|
|
if checkPassed then
|
|
-- Show display and handle clones
|
|
WeakAuras.SetDynamicIconCache(name, spellId, icon);
|
|
if(data.autoclone) then
|
|
local cloneId = name .. spellId .."-"..(casGUID or "unknown");
|
|
if (WeakAuras.SetAuraVisibility(id, triggernum, cloneId, data.buffShowOn, data.unitExists, true, unit, duration, expirationTime, name, icon, count, index, spellId, unitCaster)) then
|
|
updateTriggerState = true;
|
|
end
|
|
active = true;
|
|
cloneIdList[cloneId] = true;
|
|
-- Simply show display (show)
|
|
else
|
|
if (WeakAuras.SetAuraVisibility(id, triggernum, nil, data.buffShowOn, data.unitExists, true, unit, duration, expirationTime, name, icon, count, index, spellId, unitCaster)) then
|
|
updateTriggerState = true;
|
|
end
|
|
active = true;
|
|
break;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Update display visibility and clones visibility (hide)
|
|
if not(active) then
|
|
local nameFromTrigger, iconFromTrigger;
|
|
nameFromTrigger, iconFromTrigger = GetNameAndIconFromTrigger(data);
|
|
if (WeakAuras.SetAuraVisibility(id, triggernum, nil, data.buffShowOn, data.unitExists, nil, unit, 0, math.huge, nameFromTrigger, iconFromTrigger)) then
|
|
updateTriggerState = true;
|
|
end
|
|
end
|
|
if(data.autoclone) then
|
|
WeakAuras.SetAllStatesHiddenExcept(id, triggernum, cloneIdList);
|
|
updateTriggerState = true;
|
|
end
|
|
|
|
-- Not using full aura scan
|
|
else
|
|
-- Reset clone list
|
|
if groupcloneToUpdate then wipe(groupcloneToUpdate); end
|
|
if(aura_object and data.groupclone and not data.specificUnit and not groupcloneToUpdate) then
|
|
groupcloneToUpdate = {};
|
|
end
|
|
|
|
-- Check all selected auras (for one trigger)
|
|
|
|
local bestDuration, bestExpirationTime, bestName, bestIcon, bestCount, bestCasGUID, bestSpellId, bestUnitCaster;
|
|
|
|
for index, checkname in pairs(data.names) do
|
|
-- Fetch aura data
|
|
local detected
|
|
for i = 1, BUFF_MAX_DISPLAY do
|
|
name, rank, icon, count, _, duration, expirationTime, unitCaster, isStealable, _, spellId = UnitAura(unit, i, filter);
|
|
if not name then break end
|
|
if name == checkname then
|
|
detected = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if (detected) then
|
|
WeakAuras.SetDynamicIconCache(name, spellId, icon);
|
|
end
|
|
checkPassed = false;
|
|
|
|
-- Aura conforms to trigger options?
|
|
if(name and ((not data.count) or data.count(count)) and (data.ownOnly ~= false or not UnitIsUnit("player", unitCaster or ""))) then
|
|
remaining = expirationTime - time;
|
|
checkPassed = true;
|
|
if(data.remFunc) then
|
|
if not(data.remFunc(remaining)) then
|
|
checkPassed = false;
|
|
end
|
|
|
|
-- Schedule remaining time, re-scan later
|
|
if(remaining > data.rem) then
|
|
WeakAuras.ScheduleAuraScan(unit, time + (remaining - data.rem));
|
|
end
|
|
end
|
|
end
|
|
|
|
local casGUID = unitCaster and UnitGUID(unitCaster);
|
|
|
|
-- Aura conforms to trigger
|
|
if(checkPassed) then
|
|
active = true;
|
|
|
|
if (not bestExpirationTime or expirationTime > bestExpirationTime) then
|
|
bestDuration = duration;
|
|
bestExpirationTime = expirationTime;
|
|
bestName = name;
|
|
bestIcon = icon;
|
|
bestCount = count;
|
|
bestCasGUID = casGUID;
|
|
bestSpellId = spellId;
|
|
bestUnitCaster = unitCaster;
|
|
end
|
|
end
|
|
end
|
|
|
|
local satisfies_ignoreSelf = not data.ignoreSelf or not UnitIsUnit(unit, "player")
|
|
if not satisfies_ignoreSelf then
|
|
active = false
|
|
end
|
|
|
|
-- Update aura cache (and clones)
|
|
if (active) then
|
|
if(aura_object and not data.specificUnit) then
|
|
aura_object:AssertAura(id, triggernum, uGUID, bestDuration, bestExpirationTime, bestName, bestIcon, bestCount, bestCasGUID, bestSpellId, bestUnitCaster);
|
|
if(data.groupclone) then
|
|
groupcloneToUpdate[uGUID] = GetUnitName(unit, true);
|
|
end
|
|
else
|
|
if (WeakAuras.SetAuraVisibility(id, triggernum, nil, data.buffShowOn, data.unitExists, true, unit, bestDuration, bestExpirationTime, bestName, bestIcon, bestCount, nil, bestSpellId, bestUnitCaster)) then
|
|
updateTriggerState = true;
|
|
end
|
|
end
|
|
else
|
|
if(aura_object and not data.specificUnit) then
|
|
-- Update aura cache (and clones)
|
|
aura_object:DeassertAura(id, triggernum, uGUID);
|
|
if(data.groupclone) then
|
|
groupcloneToUpdate[uGUID] = GetUnitName(unit, true);
|
|
end
|
|
else
|
|
local nameFromTrigger, iconFromTrigger;
|
|
nameFromTrigger, iconFromTrigger = GetNameAndIconFromTrigger(data);
|
|
if (WeakAuras.SetAuraVisibility(id, triggernum, nil, data.buffShowOn, data.unitExists, nil, unit, 0, math.huge, nameFromTrigger, iconFromTrigger)) then
|
|
updateTriggerState = true;
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Processing a unit=group related unit
|
|
if(aura_object and not data.specificUnit) then
|
|
-- unit=group require valid count function
|
|
if(data.group_count) then
|
|
-- Query count from aura cache
|
|
local aura_count = aura_object:GetNumber(id, triggernum, data)
|
|
local max = aura_object:GetMaxNumber();
|
|
if (data.ignoreSelf) then
|
|
max = max - 1;
|
|
end
|
|
local satisfies_count = data.group_count(aura_count, max);
|
|
|
|
if(data.hideAlone and not IsInGroup()) then
|
|
satisfies_count = false;
|
|
end
|
|
|
|
-- Satisfying count condition
|
|
if(satisfies_count) then
|
|
-- Update clones (show)
|
|
if(data.groupclone) then
|
|
for guid, playerName in pairs(aura_cache.players) do
|
|
local duration, expirationTime, name, icon, count, spellId, unitCaster = aura_object:GetPlayerDynamicInfo(id, triggernum, guid, data);
|
|
if(name ~= "") then
|
|
if (WeakAuras.SetAuraVisibility(id, triggernum, playerName, data.buffShowOn, data.unitExists, true, unit, duration, expirationTime, playerName, icon, count, nil, spellId, unitCaster)) then
|
|
updateTriggerState = true;
|
|
end
|
|
else
|
|
if (WeakAuras.SetAuraVisibility(id, triggernum, playerName, data.buffShowOn, data.unitExists, nil, unit, duration, expirationTime, playerName, icon, count, nil, spellId, unitCaster)) then
|
|
updateTriggerState = true;
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Update display information
|
|
else
|
|
-- Get display related information
|
|
local duration, expirationTime, name, icon, count, spellId, unitCaster = aura_object:GetDynamicInfo(id, triggernum, data);
|
|
|
|
-- Process affected players
|
|
if(data.name_info == "players") then
|
|
local affected = aura_object:GetAffected(id, triggernum, data);
|
|
local num = 0;
|
|
name = "";
|
|
for affected_name, _ in pairs(affected) do
|
|
local space = affected_name:find(" ");
|
|
name = name..(space and affected_name:sub(1, space - 1).."*" or affected_name)..", ";
|
|
num = num + 1;
|
|
end
|
|
if(num == 0) then
|
|
name = WeakAuras.L["None"];
|
|
else
|
|
name = name:sub(1, -3);
|
|
end
|
|
-- Process unaffected players
|
|
elseif(data.name_info == "nonplayers") then
|
|
local unaffected = aura_object:GetUnaffected(id, triggernum, data);
|
|
local num = 0;
|
|
name = "";
|
|
for unaffected_name, _ in pairs(unaffected) do
|
|
local space = unaffected_name:find(" ");
|
|
name = name..(space and unaffected_name:sub(1, space - 1).."*" or unaffected_name)..", ";
|
|
num = num + 1;
|
|
end
|
|
if(num == 0) then
|
|
name = WeakAuras.L["None"];
|
|
else
|
|
name = name:sub(1, -3);
|
|
end
|
|
end
|
|
|
|
-- Process stacks/aura count
|
|
if(data.stack_info == "count") then
|
|
count = aura_count;
|
|
end
|
|
|
|
-- Update display visibility (show)
|
|
if (WeakAuras.SetAuraVisibility(id, triggernum, nil, data.buffShowOn, data.unitExists, true, unit, duration, expirationTime, name, icon, count, nil, spellId, unitCaster)) then
|
|
updateTriggerState = true;
|
|
end
|
|
end
|
|
|
|
-- Not satisfying count
|
|
else
|
|
-- Update clones
|
|
if(data.groupclone) then
|
|
WeakAuras.SetAllStatesHidden(id, triggernum);
|
|
updateTriggerState = true;
|
|
-- Update display visibility (hide)
|
|
else
|
|
local nameFromTrigger, iconFromTrigger;
|
|
nameFromTrigger, iconFromTrigger = GetNameAndIconFromTrigger(data);
|
|
if (WeakAuras.SetAuraVisibility(id, triggernum, nil, data.buffShowOn, data.unitExists, nil, unit, 0, math.huge, nameFromTrigger, iconFromTrigger)) then
|
|
updateTriggerState = true;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if (updateTriggerState) then
|
|
WeakAuras.UpdatedTriggerState(id);
|
|
end
|
|
WeakAuras.StopProfileAura(id);
|
|
end
|
|
end
|
|
|
|
-- Update current unit once again
|
|
WeakAuras.CurrentUnit = old_unit;
|
|
end
|
|
|
|
function WeakAuras.ScanAurasGroup()
|
|
if IsInRaid() then
|
|
for i=1, GetNumGroupMembers() do
|
|
WeakAuras.ScanAuras(WeakAuras.raidUnits[i])
|
|
end
|
|
elseif IsInGroup() then
|
|
for i=1, GetNumSubgroupMembers() do
|
|
WeakAuras.ScanAuras(WeakAuras.partyUnits[i])
|
|
end
|
|
WeakAuras.ScanAuras("player")
|
|
else
|
|
WeakAuras.ScanAuras("player")
|
|
end
|
|
end
|
|
|
|
local function GroupRosterUpdate(event)
|
|
WeakAuras.StartProfileSystem("bufftrigger");
|
|
aura_cache.TANK = 0;
|
|
aura_cache.HEALER = 0;
|
|
aura_cache.DAMAGER = 0;
|
|
aura_cache.playerRole = "NONE";
|
|
local recheck = false;
|
|
local groupMembers,playerName,uid,guid, role = {};
|
|
if IsInRaid() then
|
|
for i=1, GetNumGroupMembers() do
|
|
uid = WeakAuras.raidUnits[i];
|
|
role = UnitGroupRolesAssigned(uid)
|
|
if aura_cache[role] then
|
|
aura_cache[role] = aura_cache[role] + 1;
|
|
end
|
|
playerName = GetUnitName(uid,true);
|
|
if playerName then
|
|
playerName = playerName:gsub("-", " - ");
|
|
else
|
|
recheck = true;
|
|
end
|
|
if (playerName == UNKNOWNOBJECT) then
|
|
recheck = true;
|
|
end
|
|
guid = UnitGUID(uid);
|
|
if (guid) then
|
|
groupMembers[guid] = playerName;
|
|
end
|
|
end
|
|
role = UnitGroupRolesAssigned("player")
|
|
aura_cache.playerRole = role;
|
|
elseif IsInGroup() then
|
|
for i=1, GetNumSubgroupMembers() do
|
|
uid = WeakAuras.partyUnits[i];
|
|
role = UnitGroupRolesAssigned(uid)
|
|
if (aura_cache[role]) then
|
|
aura_cache[role] = aura_cache[role] + 1;
|
|
end
|
|
guid = UnitGUID(uid);
|
|
local playerName = GetUnitName(uid,true);
|
|
if (playerName == UNKNOWNOBJECT) then
|
|
recheck = true;
|
|
end
|
|
if (guid) then
|
|
groupMembers[guid] = playerName;
|
|
end
|
|
end
|
|
role = UnitGroupRolesAssigned("player")
|
|
if (aura_cache[role]) then
|
|
aura_cache[role] = aura_cache[role] + 1;
|
|
aura_cache.playerRole = role;
|
|
end
|
|
end
|
|
|
|
if (not WeakAuras.myGUID) then
|
|
WeakAuras.myGUID = UnitGUID("player")
|
|
end
|
|
groupMembers[WeakAuras.myGUID] = WeakAuras.me;
|
|
aura_cache:AssertMemberList(groupMembers);
|
|
if (recheck) then
|
|
timer:ScheduleTimer(GroupRosterUpdate, 0.5);
|
|
end
|
|
WeakAuras.StopProfileSystem("bufftrigger");
|
|
end
|
|
|
|
local groupFrame = CreateFrame("FRAME");
|
|
WeakAuras.frames["Group Makeup Handler"] = groupFrame;
|
|
groupFrame:RegisterEvent("PARTY_MEMBERS_CHANGED");
|
|
groupFrame:RegisterEvent("RAID_ROSTER_UPDATE");
|
|
groupFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
|
|
groupFrame:SetScript("OnEvent", function(self, event)
|
|
GroupRosterUpdate();
|
|
end);
|
|
|
|
do
|
|
local pendingTracks = {};
|
|
local UIDsfromGUID = {};
|
|
local GUIDfromUID = {};
|
|
|
|
function WeakAuras.ReleaseUID(UID)
|
|
if(GUIDfromUID[UID]) then
|
|
if(UIDsfromGUID[GUIDfromUID[UID]] and UIDsfromGUID[GUIDfromUID[UID]][UID]) then
|
|
UIDsfromGUID[GUIDfromUID[UID]][UID] = nil;
|
|
else
|
|
-- If this code is reached, it means there was some kind of coordination error between the two lists
|
|
-- This shouldn't ever happen, but it is recoverable
|
|
-- Search through the whole UIDsfromGUID table and remove all instances of UID
|
|
for GUID,UIDs in pairs(UIDsfromGUID) do
|
|
for iUID,v in pairs(UIDs) do
|
|
if(iUID == UID or iUID == UID) then
|
|
UIDs[iUID] = nil;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
GUIDfromUID[UID] = nil;
|
|
end
|
|
|
|
function WeakAuras.SetUID(GUID, UID)
|
|
WeakAuras.ReleaseUID(UID);
|
|
if not(UIDsfromGUID[GUID]) then
|
|
UIDsfromGUID[GUID] = {};
|
|
end
|
|
UIDsfromGUID[GUID][UID] = true;
|
|
GUIDfromUID[UID] = GUID;
|
|
end
|
|
|
|
function WeakAuras.GetUID(GUID)
|
|
if not(UIDsfromGUID[GUID]) then
|
|
return nil;
|
|
end
|
|
-- iterate through key/value pairs from the table of UIDs that are registered for this GUID, until a *confirmed* match is found
|
|
-- confirming is necessary in case UIDs are not always released correctly (which may actually be close to impossible)
|
|
for returnUID,v in pairs(UIDsfromGUID[GUID]) do
|
|
-- check the validity of this entry
|
|
if(UnitGUID(returnUID) == GUID) then
|
|
return returnUID;
|
|
else
|
|
WeakAuras.ReleaseUID(returnUID);
|
|
end
|
|
end
|
|
return nil;
|
|
end
|
|
|
|
--- Updates region data to see if states changed.
|
|
-- @param id
|
|
-- @param data
|
|
-- @param triggernum
|
|
-- @param GUID
|
|
-- @return boolean
|
|
local function updateRegion(id, data, triggernum, GUID)
|
|
local auradata = data.GUIDs[GUID];
|
|
local triggerState = WeakAuras.GetTriggerStateForTrigger(id, triggernum);
|
|
triggerState[GUID] = triggerState[GUID] or {};
|
|
local state = triggerState[GUID];
|
|
if (state.progressType ~= "timed") then
|
|
state.progressType = "timed";
|
|
state.changed = true;
|
|
end
|
|
|
|
if(auradata and auradata.unitName) then
|
|
if (state.show ~= true) then
|
|
state.show = true;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.expirationTime ~= auradata.expirationTime) then
|
|
state.expirationTime = auradata.expirationTime;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.duration ~= auradata.duration) then
|
|
state.duration = auradata.duration;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.autoHide ~= true) then
|
|
state.autoHide = true;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.name ~= auradata.unitName) then
|
|
state.name = auradata.unitName;
|
|
state.changed = true;
|
|
end
|
|
|
|
local icon = auradata.icon or WeakAuras.GetDynamicIconCache(auradata.name) or "Interface\\Icons\\INV_Misc_QuestionMark";
|
|
if (state.icon ~= icon) then
|
|
state.icon = icon;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.stacks ~= auradata.count) then
|
|
state.stacks = auradata.count;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.unitCaster ~= auradata.unitCaster) then
|
|
state.unitCaster = auradata.unitCaster;
|
|
state.changed = true;
|
|
end
|
|
|
|
if (state.GUID ~= GUID) then
|
|
state.GUID = GUID;
|
|
state.changed = true;
|
|
end
|
|
else
|
|
if (state.show ~= false) then
|
|
state.show = false;
|
|
state.changed = true;
|
|
end
|
|
end
|
|
|
|
if (state.changed) then
|
|
return true;
|
|
end
|
|
return false;
|
|
end
|
|
|
|
local function updateSpell(spellName, unit, destGUID)
|
|
if (not loaded_auras[spellName]) then return end;
|
|
for id, triggers in pairs(loaded_auras[spellName]) do
|
|
WeakAuras.StartProfileAura(id);
|
|
local updateTriggerState = false;
|
|
for triggernum, data in pairs(triggers) do
|
|
local filter = data.debuffType..(data.ownOnly and "|PLAYER" or "");
|
|
local detected
|
|
local name, rank, icon, count, duration, expirationTime, unitCaster, spellId, _
|
|
for i = 1, BUFF_MAX_DISPLAY do
|
|
name, rank, icon, count, _, duration, expirationTime, unitCaster, _, _, spellId = UnitAura(unit, i, filter);
|
|
if not name then break end
|
|
if name == spellName then
|
|
detected = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if(detected and (data.spellId == nil or data.spellId == spellId)) then
|
|
data.GUIDs = data.GUIDs or {};
|
|
data.GUIDs[destGUID] = data.GUIDs[destGUID] or {};
|
|
data.GUIDs[destGUID].name = spellName;
|
|
data.GUIDs[destGUID].unitName = GetUnitName(unit, true);
|
|
data.GUIDs[destGUID].duration = duration;
|
|
data.GUIDs[destGUID].expirationTime = expirationTime;
|
|
data.GUIDs[destGUID].icon = icon;
|
|
data.GUIDs[destGUID].count = count;
|
|
data.GUIDs[destGUID].unitCaster = unitCaster and UnitName(unitCaster);
|
|
data.GUIDs[destGUID].spellId = spellId;
|
|
updateTriggerState = updateRegion(id, data, triggernum, destGUID) or updateTriggerState;
|
|
end
|
|
end
|
|
if (updateTriggerState) then
|
|
WeakAuras.UpdatedTriggerState(id);
|
|
end
|
|
WeakAuras.StopProfileAura(id);
|
|
end
|
|
end
|
|
|
|
local function combatLog(_, event, _, sourceName, _, destGUID, destName, _, spellId, spellName, _, auraType, amount)
|
|
if(loaded_auras[spellName]) then
|
|
if(message == "SPELL_AURA_APPLIED" or message == "SPELL_AURA_REFRESH" or message == "SPELL_AURA_APPLIED_DOSE" or message == "SPELL_AURA_REMOVED_DOSE") then
|
|
local unit = WeakAuras.GetUID(destGUID);
|
|
if(unit) then
|
|
updateSpell(spellName, unit, destGUID);
|
|
else
|
|
for id, triggers in pairs(loaded_auras[spellName]) do
|
|
WeakAuras.StartProfileAura(id);
|
|
local updateTriggerState = false;
|
|
for triggernum, data in pairs(triggers) do
|
|
if((not data.ownOnly) or UnitIsUnit(sourceName or "", "player")) then
|
|
pendingTracks[destGUID] = pendingTracks[destGUID] or {};
|
|
pendingTracks[destGUID][spellName] = true;
|
|
|
|
data.GUIDs = data.GUIDs or {};
|
|
data.GUIDs[destGUID] = data.GUIDs[destGUID] or {};
|
|
data.GUIDs[destGUID].name = spellName;
|
|
data.GUIDs[destGUID].unitName = destName;
|
|
local icon = spellId and select(3, GetSpellInfo(spellId));
|
|
if (message == "SPELL_AURA_APPLIED_DOSE" or message == "SPELL_AURA_REMOVED_DOSE") then
|
|
-- Shouldn't affect duration/expirationTime nor icon
|
|
data.GUIDs[destGUID].duration = data.GUIDs[destGUID].duration or 0;
|
|
data.GUIDs[destGUID].expirationTime = data.GUIDs[destGUID].expirationTime or math.huge;
|
|
data.GUIDs[destGUID].icon = data.GUIDs[destGUID].icon or icon;
|
|
else
|
|
data.GUIDs[destGUID].duration = 0;
|
|
data.GUIDs[destGUID].expirationTime = math.huge;
|
|
data.GUIDs[destGUID].icon = icon;
|
|
end
|
|
data.GUIDs[destGUID].count = amount or 0;
|
|
data.GUIDs[destGUID].spellId = spellId;
|
|
data.GUIDs[destGUID].unitCaster = sourceName and UnitName(sourceName);
|
|
|
|
updateTriggerState = updateRegion(id, data, triggernum, destGUID) or updateTriggerState;
|
|
end
|
|
end
|
|
if (updateTriggerState) then
|
|
WeakAuras.UpdatedTriggerState(id);
|
|
end
|
|
WeakAuras.StopProfileAura(id);
|
|
end
|
|
end
|
|
elseif(message == "SPELL_AURA_REMOVED") then
|
|
for id, triggers in pairs(loaded_auras[spellName]) do
|
|
local updateTriggerState = false;
|
|
for triggernum, data in pairs(triggers) do
|
|
if((not data.ownOnly) or UnitIsUnit(sourceName or "", "player")) then
|
|
-- WeakAuras.debug("Removed "..spellName.." from "..destGUID.." ("..(data.GUIDs and data.GUIDs[destGUID] and data.GUIDs[destGUID].unitName or "error")..") - "..(data.ownOnly and "own only" or "not own only")..", "..sourceName, 3);
|
|
data.GUIDs = data.GUIDs or {};
|
|
data.GUIDs[destGUID] = nil;
|
|
|
|
updateTriggerState = updateRegion(id, data, triggernum, destGUID) or updateTriggerState;
|
|
end
|
|
end
|
|
if (updateTriggerState) then
|
|
WeakAuras.UpdatedTriggerState(id);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function uidTrack(unit)
|
|
local GUID = UnitGUID(unit);
|
|
if(GUID) then
|
|
WeakAuras.SetUID(GUID, unit);
|
|
if(pendingTracks[GUID]) then
|
|
for spellName,_ in pairs(pendingTracks[GUID]) do
|
|
updateSpell(spellName, unit, GUID);
|
|
pendingTracks[GUID][spellName] = nil;
|
|
end
|
|
end
|
|
else
|
|
WeakAuras.ReleaseUID(unit);
|
|
end
|
|
unit = unit.."target";
|
|
GUID = UnitGUID(unit);
|
|
if(GUID) then
|
|
WeakAuras.SetUID(GUID, unit);
|
|
if(pendingTracks[GUID]) then
|
|
for spellName,_ in pairs(pendingTracks[GUID]) do
|
|
updateSpell(spellName, unit, GUID);
|
|
pendingTracks[GUID][spellName] = nil;
|
|
end
|
|
end
|
|
else
|
|
WeakAuras.ReleaseUID(unit);
|
|
end
|
|
end
|
|
|
|
local function checkExists()
|
|
WeakAuras.StartProfileSystem("bufftrigger - multi");
|
|
for unit, auras in pairs(loaded_auras) do
|
|
if not(WeakAuras.unit_types[unit]) then
|
|
for id, triggers in pairs(auras) do
|
|
WeakAuras.StartProfileAura(id);
|
|
local updateTriggerState = false;
|
|
for triggernum, data in pairs(triggers) do
|
|
if(data.GUIDs) then
|
|
for GUID, GUIDData in pairs(data.GUIDs) do
|
|
if(GUIDData.expirationTime and GUIDData.expirationTime + 2 < GetTime()) then
|
|
data.GUIDs[GUID] = nil;
|
|
updateTriggerState = updateRegion(id, data, triggernum, GUID) or updateTriggerState;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if (updateTriggerState) then
|
|
WeakAuras.UpdatedTriggerState(id);
|
|
end
|
|
WeakAuras.StopProfileAura(id);
|
|
end
|
|
end
|
|
end
|
|
WeakAuras.StopProfileSystem("bufftrigger - multi");
|
|
end
|
|
|
|
local function handleEvent(frame, event, ...)
|
|
WeakAuras.StartProfileSystem("bufftrigger - multi");
|
|
if(event == "COMBAT_LOG_EVENT_UNFILTERED") then
|
|
combatLog(...);
|
|
elseif(event == "UNIT_TARGET") then
|
|
uidTrack(...);
|
|
elseif(event == "PLAYER_FOCUS_CHANGED") then
|
|
uidTrack("focus");
|
|
elseif(event == "NAME_PLATE_UNIT_ADDED") then
|
|
uidTrack(...);
|
|
elseif(event == "NAME_PLATE_UNIT_REMOVED") then
|
|
local unit = ...
|
|
WeakAuras.ReleaseUID(unit);
|
|
unit = unit.."target";
|
|
WeakAuras.ReleaseUID(unit);
|
|
elseif(event == "UNIT_AURA") then
|
|
-- Note: Using UNIT_AURA in addition to COMBAT_LOG_EVENT_UNFILTERED,
|
|
-- because the combat log event does not contain duration information
|
|
local uid = ...;
|
|
if not uid then return end
|
|
local guid = UnitGUID(uid);
|
|
|
|
for spellName, auras in pairs(loaded_auras) do
|
|
if not(WeakAuras.unit_types[spellName]) then
|
|
for id, triggers in pairs(auras) do
|
|
WeakAuras.StartProfileAura(id);
|
|
local updateTriggerState = false;
|
|
for triggernum, data in pairs(triggers) do
|
|
local filter = data.debuffType..(data.ownOnly and "|PLAYER" or "");
|
|
|
|
local detected
|
|
local name, rank, icon, count, duration, expirationTime, unitCaster, _
|
|
for i = 1, BUFF_MAX_DISPLAY do
|
|
name, rank, icon, count, _, duration, expirationTime, unitCaster = UnitAura(uid, i, filter);
|
|
if not name then break end
|
|
if name == spellName then
|
|
detected = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if(detected) then
|
|
data.GUIDs = data.GUIDs or {};
|
|
data.GUIDs[guid] = data.GUIDs[guid] or {};
|
|
data.GUIDs[guid].name = spellName;
|
|
data.GUIDs[guid].unitName = GetUnitName(uid, true);
|
|
data.GUIDs[guid].duration = duration;
|
|
data.GUIDs[guid].expirationTime = expirationTime;
|
|
data.GUIDs[guid].icon = icon;
|
|
data.GUIDs[guid].count = count;
|
|
data.GUIDs[guid].unitCaster = unitCaster and UnitName(unitCaster);
|
|
updateTriggerState = updateRegion(id, data, triggernum, guid) or updateTriggerState;
|
|
end
|
|
end
|
|
if (updateTriggerState) then
|
|
WeakAuras.UpdatedTriggerState(id);
|
|
end
|
|
WeakAuras.StopProfileAura(id);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
WeakAuras.StopProfileSystem("bufftrigger - multi");
|
|
end
|
|
|
|
local combatAuraFrame;
|
|
function WeakAuras.InitMultiAura()
|
|
if not(combatAuraFrame) then
|
|
combatAuraFrame = CreateFrame("frame");
|
|
combatAuraFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
|
|
combatAuraFrame:RegisterEvent("UNIT_TARGET");
|
|
combatAuraFrame:RegisterEvent("UNIT_AURA");
|
|
combatAuraFrame:RegisterEvent("PLAYER_FOCUS_CHANGED");
|
|
combatAuraFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED");
|
|
combatAuraFrame:RegisterEvent("NAME_PLATE_UNIT_REMOVED");
|
|
combatAuraFrame:RegisterEvent("PLAYER_LEAVING_WORLD");
|
|
combatAuraFrame:SetScript("OnEvent", handleEvent);
|
|
WeakAuras.frames["Multi-target Aura Trigger Handler"] = combatAuraFrame;
|
|
timer:ScheduleRepeatingTimer(checkExists, 10)
|
|
end
|
|
end
|
|
end
|
|
|
|
do
|
|
local scheduled_scans = {};
|
|
|
|
function WeakAuras.ScheduleAuraScan(unit, fireTime)
|
|
scheduled_scans[unit] = scheduled_scans[unit] or {};
|
|
if not(scheduled_scans[unit][fireTime]) then
|
|
WeakAuras.debug("Scheduled aura scan for "..unit.." at "..fireTime);
|
|
local doScan = function()
|
|
WeakAuras.debug("Performing aura scan for "..unit.." at "..fireTime.." ("..GetTime()..")");
|
|
scheduled_scans[unit][fireTime] = nil;
|
|
WeakAuras.ScanAuras(unit);
|
|
end
|
|
scheduled_scans[unit][fireTime] = timer:ScheduleTimerFixed(doScan, fireTime - GetTime() + 0.1);
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Adds auras to the loaded_auras table
|
|
-- @param id
|
|
-- @param triggernum
|
|
-- @param data
|
|
local function LoadAura(id, triggernum, data)
|
|
local unit;
|
|
if(data.specificUnit) then
|
|
if(data.unit:lower():sub(1,4) == "boss") then
|
|
specificBosses[data.unit] = true;
|
|
unit = "boss";
|
|
elseif(data.unit:lower():sub(1,5) == "arena") then
|
|
unit = "arena";
|
|
else
|
|
specificUnits[data.unit] = true;
|
|
unit = "group";
|
|
end
|
|
elseif(data.unit == "multi") then
|
|
unit = data.name
|
|
else
|
|
unit = data.unit;
|
|
end
|
|
if(unit) then
|
|
loaded_auras[unit] = loaded_auras[unit] or {};
|
|
loaded_auras[unit][id] = loaded_auras[unit][id] or {};
|
|
loaded_auras[unit][id][triggernum] = data;
|
|
end
|
|
end
|
|
|
|
function BuffTrigger.ScanAll()
|
|
local unitIdstoScan = {};
|
|
local groupScan = false;
|
|
for unit, auras in pairs(loaded_auras) do
|
|
if(unit == "group") then
|
|
groupScan = true;
|
|
elseif(WeakAuras.unit_types[unit]) then
|
|
unitIdstoScan[unit] = true;
|
|
end
|
|
end
|
|
|
|
if (groupScan) then
|
|
WeakAuras.ScanAurasGroup();
|
|
end
|
|
|
|
for unit, _ in pairs(unitIdstoScan) do
|
|
WeakAuras.ScanAuras(unit);
|
|
end
|
|
end
|
|
|
|
local aura_scan_cooldowns = {};
|
|
local checkingScanCooldowns;
|
|
local scanCooldownFrame = CreateFrame("frame");
|
|
WeakAuras.frames["Aura Scan Cooldown"] = scanCooldownFrame;
|
|
|
|
local checkScanCooldownsFunc = function()
|
|
WeakAuras.StartProfileSystem("bufftrigger")
|
|
for unit,_ in pairs(aura_scan_cooldowns) do
|
|
aura_scan_cooldowns[unit] = nil;
|
|
WeakAuras.ScanAuras(unit);
|
|
end
|
|
checkingScanCooldowns = nil;
|
|
scanCooldownFrame:SetScript("OnUpdate", nil);
|
|
WeakAuras.StopProfileSystem("bufftrigger")
|
|
end
|
|
|
|
local frame = CreateFrame("FRAME");
|
|
WeakAuras.frames["WeakAuras Buff Frame"] = frame;
|
|
frame:RegisterEvent("PLAYER_ENTERING_WORLD");
|
|
frame:RegisterEvent("PLAYER_FOCUS_CHANGED");
|
|
frame:RegisterEvent("PLAYER_TARGET_CHANGED");
|
|
frame:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT");
|
|
frame:RegisterEvent("UNIT_AURA");
|
|
frame:RegisterEvent("UNIT_PET")
|
|
frame:SetScript("OnEvent", function (frame, event, arg1, arg2, ...)
|
|
if (WeakAuras.IsPaused()) then return end;
|
|
WeakAuras.StartProfileSystem("bufftrigger");
|
|
if (event == "PLAYER_ENTERING_WORLD") then
|
|
BuffTrigger.ScanAll();
|
|
elseif(event == "PLAYER_TARGET_CHANGED") then
|
|
WeakAuras.ScanAuras("target");
|
|
elseif(event == "PLAYER_FOCUS_CHANGED") then
|
|
WeakAuras.ScanAuras("focus");
|
|
elseif(event == "UNIT_PET" and arg1 == "player") then
|
|
WeakAuras.ScanAuras("pet");
|
|
elseif(event == "INSTANCE_ENCOUNTER_ENGAGE_UNIT") then
|
|
for unit,_ in pairs(specificBosses) do
|
|
WeakAuras.ScanAuras(unit);
|
|
end
|
|
elseif(event == "UNIT_AURA") then
|
|
if not arg1 then return end
|
|
if(
|
|
loaded_auras[arg1]
|
|
or (
|
|
loaded_auras["group"]
|
|
and (
|
|
arg1:sub(1, 4) == "raid"
|
|
or arg1:sub(1, 5) == "party"
|
|
or arg1 == "player"
|
|
)
|
|
)
|
|
or (
|
|
loaded_auras["boss"]
|
|
and arg1:sub(1,4) == "boss"
|
|
)
|
|
or (
|
|
loaded_auras["arena"]
|
|
and arg1:sub(1,5) == "arena"
|
|
)
|
|
) then
|
|
-- This throttles aura scans to only happen at most once per frame per unit
|
|
if not(aura_scan_cooldowns[arg1]) then
|
|
aura_scan_cooldowns[arg1] = true;
|
|
if not(checkingScanCooldowns) then
|
|
checkingScanCooldowns = true;
|
|
scanCooldownFrame:SetScript("OnUpdate", checkScanCooldownsFunc);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
WeakAuras.StopProfileSystem("bufftrigger");
|
|
end);
|
|
|
|
function BuffTrigger.UnloadAll()
|
|
wipe(loaded_auras);
|
|
end
|
|
|
|
function BuffTrigger.LoadDisplays(toLoad)
|
|
for id in pairs(toLoad) do
|
|
if(auras[id]) then
|
|
for triggernum, data in pairs(auras[id]) do
|
|
if(auras[id] and auras[id][triggernum]) then
|
|
LoadAura(id, triggernum, data);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function BuffTrigger.UnloadDisplays(toUnload)
|
|
for id in pairs(toUnload) do
|
|
for unitname, auras in pairs(loaded_auras) do
|
|
auras[id] = nil;
|
|
end
|
|
end
|
|
end
|
|
|
|
function BuffTrigger.FinishLoadUnload()
|
|
BuffTrigger.ScanAll();
|
|
end
|
|
|
|
--- Removes all data for an aura id
|
|
-- @param id
|
|
function BuffTrigger.Delete(id)
|
|
auras[id] = nil;
|
|
for i,v in pairs(loaded_auras) do
|
|
v[id] = nil;
|
|
end
|
|
end
|
|
|
|
--- Updates all data for aura oldid to use newid
|
|
-- @param oldid
|
|
-- @param newid
|
|
function BuffTrigger.Rename(oldid, newid)
|
|
auras[newid] = auras[oldid];
|
|
auras[oldid] = nil;
|
|
|
|
aura_cache:Rename(oldid, newid);
|
|
|
|
for i,v in pairs(loaded_auras) do
|
|
v[newid] = v[oldid];
|
|
v[newid] = nil;
|
|
end
|
|
end
|
|
|
|
--- Adds an aura, setting up internal data structures for all buff triggers.
|
|
-- @param data
|
|
function BuffTrigger.Add(data)
|
|
local id = data.id;
|
|
auras[id] = nil;
|
|
|
|
for triggernum, triggerData in ipairs(data.triggers) do
|
|
local trigger, untrigger = triggerData.trigger, triggerData.untrigger
|
|
local triggerType;
|
|
if(type(trigger) == "table") then
|
|
triggerType = trigger.type;
|
|
if(triggerType == "aura") then
|
|
trigger.names = trigger.names or {};
|
|
trigger.spellIds = trigger.spellIds or {}
|
|
trigger.unit = trigger.unit or "player";
|
|
trigger.debuffType = trigger.debuffType or "HELPFUL";
|
|
|
|
local countFunc, countFuncStr;
|
|
if(trigger.useCount) then
|
|
countFuncStr = function_strings.count:format(trigger.countOperator or ">=", tonumber(trigger.count) or 0);
|
|
countFunc = WeakAuras.LoadFunction(countFuncStr);
|
|
end
|
|
|
|
local remFunc, remFuncStr;
|
|
if(trigger.useRem) then
|
|
remFuncStr = function_strings.count:format(trigger.remOperator or ">=", tonumber(trigger.rem) or 0);
|
|
remFunc = WeakAuras.LoadFunction(remFuncStr);
|
|
end
|
|
|
|
local group_countFunc, group_countFuncStr;
|
|
if(trigger.unit == "group") then
|
|
local count, countType = WeakAuras.ParseNumber(trigger.group_count);
|
|
if(trigger.group_countOperator and count and countType) then
|
|
if(countType == "whole") then
|
|
group_countFuncStr = function_strings.count:format(trigger.group_countOperator, count);
|
|
else
|
|
group_countFuncStr = function_strings.count_fraction:format(trigger.group_countOperator, count);
|
|
end
|
|
else
|
|
group_countFuncStr = function_strings.count:format(">", 0);
|
|
end
|
|
group_countFunc = WeakAuras.LoadFunction(group_countFuncStr);
|
|
WeakAuras.aura_cache:Watch(id, triggernum);
|
|
end
|
|
|
|
local scanFunc;
|
|
if(trigger.fullscan) then
|
|
scanFunc = function(name, tooltip, isStealable, spellId, debuffClass)
|
|
if (
|
|
(
|
|
(not trigger.use_name) or (
|
|
trigger.name and trigger.name ~= "" and (
|
|
trigger.name_operator == "==" and name == trigger.name
|
|
or trigger.name_operator == "find('%s')" and name:find(trigger.name)
|
|
or trigger.name_operator == "match('%s')" and name:match(trigger.name)
|
|
)
|
|
)
|
|
)
|
|
and (
|
|
(not trigger.use_tooltip) or (
|
|
trigger.tooltip and trigger.tooltip ~= "" and (
|
|
trigger.tooltip_operator == "==" and tooltip == trigger.tooltip
|
|
or trigger.tooltip_operator == "find('%s')" and tooltip:find(trigger.tooltip)
|
|
or trigger.tooltip_operator == "match('%s')" and tooltip:match(trigger.tooltip)
|
|
)
|
|
)
|
|
)
|
|
and ((not trigger.use_stealable) or isStealable)
|
|
and ((not trigger.use_spellId) or spellId == tonumber(trigger.spellId))
|
|
and ((not trigger.use_debuffClass) or debuffClass == trigger.debuffClass)
|
|
) then
|
|
return true;
|
|
else
|
|
return false;
|
|
end
|
|
end -- end scanFunc
|
|
end
|
|
|
|
if(trigger.unit == "multi") then
|
|
WeakAuras.InitMultiAura();
|
|
end
|
|
|
|
if (trigger.buffShowOn == nil) then
|
|
trigger.buffShowOn = "showOnActive";
|
|
end
|
|
|
|
local buffShowOn = "showOnActive";
|
|
local unitExists = true;
|
|
|
|
if (not(trigger.unit ~= "group" and trigger.autoclone) and trigger.unit ~= "multi" and trigger.unit ~= "group" and trigger.unit ~= "player") then
|
|
unitExists = trigger.unitExists;
|
|
end
|
|
|
|
if (trigger.type == "aura" and not(trigger.unit ~= "group" and trigger.autoclone)
|
|
and trigger.unit ~= "multi" and not(trigger.unit == "group" and not trigger.groupclone)) then
|
|
buffShowOn = trigger.buffShowOn;
|
|
end
|
|
|
|
auras[id] = auras[id] or {};
|
|
auras[id][triggernum] = {
|
|
count = countFunc,
|
|
remFunc = remFunc,
|
|
rem = tonumber(trigger.rem) or 0,
|
|
group_count = group_countFunc,
|
|
fullscan = trigger.fullscan,
|
|
autoclone = trigger.autoclone,
|
|
groupclone = trigger.groupclone,
|
|
subcount = trigger.subcount,
|
|
subcountCount = trigger.subcountCount,
|
|
scanFunc = scanFunc,
|
|
debuffType = trigger.debuffType,
|
|
names = trigger.names,
|
|
spellIds = trigger.spellIds,
|
|
name = trigger.name,
|
|
spellId = trigger.spellId,
|
|
unit = trigger.unit == "member" and trigger.specificUnit or trigger.unit,
|
|
specificUnit = trigger.unit == "member",
|
|
useCount = trigger.useCount,
|
|
ownOnly = trigger.ownOnly,
|
|
buffShowOn = buffShowOn,
|
|
unitExists = unitExists,
|
|
numAdditionalTriggers = max(#data.triggers - 1, 0),
|
|
hideAlone = trigger.hideAlone,
|
|
stack_info = trigger.stack_info,
|
|
name_info = trigger.name_info,
|
|
ignoreSelf = trigger.ignoreSelf
|
|
};
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Updates old data to the new format.
|
|
-- @param data
|
|
function BuffTrigger.Modernize(data)
|
|
for triggernum, triggerData in ipairs(data.triggers) do
|
|
local trigger = triggerData.trigger;
|
|
|
|
if (data.internalVersion < 2) then
|
|
if (trigger and trigger.type == "aura") then
|
|
if (trigger.showOn == nil or trigger.showOn == "showOnCooldown" or trigger.showOn == "showOnReady" or trigger.showOn == "showAlways") then
|
|
trigger.showOn = trigger.inverse and "showOnMissing" or "showOnActive";
|
|
trigger.inverse = nil;
|
|
end
|
|
end
|
|
end
|
|
|
|
if data.internalVersion < 6 then
|
|
if trigger and trigger.type == "aura" then
|
|
if trigger.showOn == "showOnMissing" then
|
|
trigger.buffShowOn = "showOnMissing"
|
|
elseif trigger.showOn == "showActiveOrMissing" then
|
|
trigger.buffShowOn = "showAlways"
|
|
else
|
|
trigger.buffShowOn = "showOnActive"
|
|
end
|
|
trigger.showOn = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Returns whether the first trigger could be shown without any affected group members.
|
|
-- @param data
|
|
-- @param triggernum
|
|
-- @return boolean
|
|
local function CanGroupShowWithZero(data, triggernum)
|
|
local trigger = data.triggers[triggernum].trigger
|
|
local group_countFunc, group_countFuncStr;
|
|
if(trigger.unit == "group") then
|
|
local count, countType = WeakAuras.ParseNumber(trigger.group_count);
|
|
if(trigger.group_countOperator and count and countType) then
|
|
if(countType == "whole") then
|
|
group_countFuncStr = function_strings.count:format(trigger.group_countOperator, count);
|
|
else
|
|
group_countFuncStr = function_strings.count_fraction:format(trigger.group_countOperator, count);
|
|
end
|
|
else
|
|
group_countFuncStr = function_strings.count:format(">", 0);
|
|
end
|
|
group_countFunc = WeakAuras.LoadFunction(group_countFuncStr);
|
|
return group_countFunc(0, 1);
|
|
else
|
|
return false;
|
|
end
|
|
end
|
|
|
|
--- Returns whether the trigger can have a duration.
|
|
-- @param data
|
|
-- @param triggernum
|
|
function BuffTrigger.CanHaveDuration(data, triggernum)
|
|
local trigger = data.triggers[triggernum].trigger
|
|
if (trigger.type == "aura" and not(trigger.unit ~= "group" and trigger.autoclone) and trigger.unit ~= "multi" and not(trigger.unit == "group" and not trigger.groupclone)) then
|
|
if (trigger.buffShowOn ~= "showOnMissing") then
|
|
return "timed";
|
|
else
|
|
return false;
|
|
end
|
|
end
|
|
return "timed";
|
|
end
|
|
|
|
--- Returns a table containing the names of all overlays
|
|
-- @param data
|
|
-- @param triggernum
|
|
function BuffTrigger.GetOverlayInfo(data, triggernum)
|
|
return {};
|
|
end
|
|
|
|
--- Returns whether the icon can be automatically selected.
|
|
-- @param data
|
|
-- @param triggernum
|
|
-- @return boolean
|
|
function BuffTrigger.CanHaveAuto(data, triggernum)
|
|
return true;
|
|
end
|
|
|
|
--- Returns whether the trigger can have clones.
|
|
-- @param data
|
|
-- @param triggernum
|
|
-- @return
|
|
function BuffTrigger.CanHaveClones(data, triggernum)
|
|
local trigger = data.triggers[triggernum].trigger
|
|
return (trigger.fullscan and trigger.autoclone)
|
|
or (trigger.unit == "group" and trigger.groupclone)
|
|
or (trigger.unit == "multi");
|
|
end
|
|
|
|
---Returns the type of tooltip to show for the trigger.
|
|
-- @param data
|
|
-- @param triggernum
|
|
-- @return string
|
|
function BuffTrigger.CanHaveTooltip(data, triggernum)
|
|
local trigger = data.triggers[triggernum].trigger
|
|
if(trigger.unit == "group" and trigger.name_info ~= "aura" and not trigger.groupclone) then
|
|
return "playerlist";
|
|
elseif(trigger.fullscan and trigger.unit ~= "group") then
|
|
return "auraindex";
|
|
else
|
|
return "aura";
|
|
end
|
|
end
|
|
|
|
function BuffTrigger.SetToolTip(trigger, state)
|
|
local data = auras[state.id][state.triggernum];
|
|
if(trigger.unit == "group" and trigger.name_info ~= "aura" and not trigger.groupclone) then
|
|
local name = "";
|
|
local playerList;
|
|
if(trigger.name_info == "players") then
|
|
playerList = WeakAuras.aura_cache:GetAffected(state.id, state.triggernum, data);
|
|
name = L["Affected"]..":";
|
|
elseif(trigger.name_info == "nonplayers") then
|
|
playerList = WeakAuras.aura_cache:GetUnaffected(state.id, state.triggernum, data);
|
|
name = L["Missing"]..":";
|
|
else
|
|
playerList = {};
|
|
end
|
|
|
|
local numPlayers = 0;
|
|
for playerName, _ in pairs(playerList) do
|
|
numPlayers = numPlayers + 1;
|
|
end
|
|
|
|
if(numPlayers > 0) then
|
|
GameTooltip:AddLine(name);
|
|
local numRaid = IsInRaid() and GetNumGroupMembers() or 0;
|
|
local groupMembers,playersString = {};
|
|
|
|
if(numRaid > 0) then
|
|
local playerName, _, subgroup
|
|
for i = 1,numRaid do
|
|
-- Battleground-name, given by GetRaidRosterInfo (name-server) to GetUnitName(...) (name - server) transition
|
|
playerName, _, subgroup = GetRaidRosterInfo(i);
|
|
|
|
if(playerName) then
|
|
playerName = playerName:gsub("-", " - ")
|
|
if (playerList[playerName]) then
|
|
groupMembers[subgroup] = groupMembers[subgroup] or {};
|
|
groupMembers[subgroup][playerName] = true
|
|
end
|
|
end
|
|
end
|
|
for subgroup, players in pairs(groupMembers) do
|
|
playersString = L["Group %s"]:format(subgroup)..": ";
|
|
local _,space,class,classColor;
|
|
for playerName, _ in pairs(players) do
|
|
space = playerName:find(" ");
|
|
_, class = UnitClass((space and playerName:sub(1, space - 1) or playerName));
|
|
classColor = WeakAuras.class_color_types[class];
|
|
playersString = playersString..(classColor or "")..(space and playerName:sub(1, space - 1).."*" or playerName)..(classColor and "|r" or "")..(next(players, playerName) and ", " or "");
|
|
end
|
|
GameTooltip:AddLine(playersString);
|
|
end
|
|
else
|
|
local num = 0;
|
|
playersString = "";
|
|
local _,space,class,classColor;
|
|
for playerName, _ in pairs(playerList) do
|
|
space = playerName:find(" ");
|
|
_, class = UnitClass((space and playerName:sub(1, space - 1) or playerName));
|
|
classColor = WeakAuras.class_color_types[class];
|
|
playersString = playersString..(classColor or "")..(space and playerName:sub(1, space - 1).."*" or playerName)..(classColor and "|r" or "")..(next(playerList, playerName) and (", "..(num % 5 == 4 and "\n" or "")) or "");
|
|
num = num + 1;
|
|
end
|
|
GameTooltip:AddLine(playersString);
|
|
end
|
|
else
|
|
GameTooltip:AddLine(name.." "..L["None"]);
|
|
end
|
|
return true
|
|
elseif(trigger.fullscan and trigger.unit ~= "group" and state.index) then
|
|
local unit = trigger.unit == "member" and trigger.specificUnit or trigger.unit;
|
|
if(trigger.debuffType == "HELPFUL") then
|
|
GameTooltip:SetUnitBuff(unit, state.index);
|
|
elseif(trigger.debuffType == "HARMFUL") then
|
|
GameTooltip:SetUnitDebuff(unit, state.index);
|
|
end
|
|
return true
|
|
else
|
|
if (state.spellId) then
|
|
GameTooltip:SetSpellByID(state.spellId);
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
--- Returns the name and icon to show in the options.
|
|
-- @param data
|
|
-- @param triggernum
|
|
-- @return name and icon
|
|
function BuffTrigger.GetNameAndIcon(data, triggernum)
|
|
local _, name, icon
|
|
local trigger = data.triggers[triggernum].trigger
|
|
if (trigger.fullscan) then
|
|
if (trigger.spellId) then
|
|
name, _, icon = GetSpellInfo(trigger.spellId);
|
|
else
|
|
name = trigger.name;
|
|
icon = WeakAuras.spellCache.GetIcon(trigger.name);
|
|
end
|
|
else
|
|
if (trigger.spellIds and trigger.spellIds[1]) then
|
|
name, _, icon = GetSpellInfo(trigger.spellIds[1])
|
|
elseif(not (trigger.buffShowOn == "showOnMissing" or CanGroupShowWithZero(data, triggernum)) and trigger.names) then
|
|
-- Try to get an icon from the icon cache
|
|
for index, checkname in pairs(trigger.names) do
|
|
local iconFromSpellCache = WeakAuras.spellCache.GetIcon(checkname);
|
|
if(iconFromSpellCache) then
|
|
name, icon = checkname, iconFromSpellCache;
|
|
break;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return name, icon;
|
|
end
|
|
|
|
--- Returns the tooltip text for additional properties.
|
|
-- @param data
|
|
-- @param triggernum
|
|
-- @return string of additional properties
|
|
function BuffTrigger.GetAdditionalProperties(data, triggernum)
|
|
local ret = "|cFFFF0000%".. triggernum .. ".spellId|r -" .. L["Spell ID"] .. "\n";
|
|
ret = ret .. "|cFFFF0000%".. triggernum .. ".unitCaster|r -" .. L["Caster"] .. "\n";
|
|
|
|
return ret;
|
|
end
|
|
|
|
function BuffTrigger.GetTriggerConditions(data, triggernum)
|
|
local result = {};
|
|
local trigger = data.triggers[triggernum].trigger
|
|
|
|
result["unitCaster"] = {
|
|
display = L["Caster"],
|
|
type = "string",
|
|
}
|
|
|
|
result["expirationTime"] = {
|
|
display = L["Remaining Duration"],
|
|
type = "timer",
|
|
}
|
|
result["duration"] = {
|
|
display = L["Total Duration"],
|
|
type = "number",
|
|
}
|
|
|
|
result["stacks"] = {
|
|
display = L["Stacks"],
|
|
type = "number"
|
|
}
|
|
|
|
result["name"] = {
|
|
display = L["Name"],
|
|
type = "string"
|
|
}
|
|
|
|
if (trigger.type == "aura" and not(trigger.unit ~= "group" and trigger.fullscan and trigger.autoclone) and trigger.unit ~= "multi" and not(trigger.unit == "group" and not trigger.groupclone)) then
|
|
if (trigger.buffShowOn == "showAlways") then
|
|
result["buffed"] = {
|
|
display = L["Buffed/Debuffed"],
|
|
type = "bool",
|
|
test = function(state, needle)
|
|
return state and state.show and ((state.active and true or false) == (needle == 1));
|
|
end
|
|
}
|
|
end
|
|
end
|
|
|
|
return result;
|
|
end
|
|
|
|
function BuffTrigger.CreateFallbackState(data, triggernum, state)
|
|
state.show = true;
|
|
state.changed = true;
|
|
state.progressType = "timed";
|
|
state.duration = 0;
|
|
state.expirationTime = math.huge;
|
|
local name, icon = GetNameAndIconFromTrigger(data, triggernum)
|
|
state.name = name
|
|
state.icon = icon
|
|
end
|
|
|
|
function BuffTrigger.GetName(triggerType)
|
|
if (triggerType == "aura") then
|
|
return L["Legacy Aura"];
|
|
end
|
|
end
|
|
|
|
function BuffTrigger.GetTriggerDescription(data, triggernum, namestable)
|
|
local trigger = data.triggers[triggernum].trigger;
|
|
if(trigger.fullscan) then
|
|
tinsert(namestable, {L["Aura:"], L["Full Scan"]});
|
|
else
|
|
for index, name in pairs(trigger.names) do
|
|
local left = " ";
|
|
if(index == 1) then
|
|
if(#trigger.names > 0) then
|
|
if(#trigger.names > 1) then
|
|
left = L["Auras:"];
|
|
else
|
|
left = L["Aura:"];
|
|
end
|
|
end
|
|
end
|
|
local icon = WeakAuras.spellCache.GetIcon(name) or "Interface\\Icons\\INV_Misc_QuestionMark";
|
|
tinsert(namestable, {left, name, icon});
|
|
end
|
|
end
|
|
end
|
|
|
|
function BuffTrigger.CreateFakeStates(id, triggernum)
|
|
local allStates = WeakAuras.GetTriggerStateForTrigger(id, triggernum);
|
|
local data = WeakAuras.GetData(id)
|
|
local state = {}
|
|
BuffTrigger.CreateFallbackState(data, triggernum, state)
|
|
state.expirationTime = GetTime() + 60
|
|
state.duration = 65
|
|
state.progressType = "timed"
|
|
allStates[""] = state
|
|
if BuffTrigger.CanHaveClones(data, triggernum) then
|
|
for i = 1, 2 do
|
|
local state = {}
|
|
BuffTrigger.CreateFallbackState(data, triggernum, state)
|
|
state.expirationTime = GetTime() + 60 + i * 20
|
|
state.duration = 100
|
|
state.progressType = "timed"
|
|
allStates[i] = state
|
|
end
|
|
end
|
|
end
|
|
|
|
WeakAuras.RegisterTriggerSystem({"aura"}, BuffTrigger);
|