179 lines
4.3 KiB
Lua
179 lines
4.3 KiB
Lua
if not WeakAuras.IsCorrectVersion() then return end
|
|
|
|
-- Lua APIs
|
|
local pairs, error, coroutine = pairs, error, coroutine
|
|
|
|
-- WoW APIs
|
|
local GetSpellInfo, IsSpellKnown = GetSpellInfo, IsSpellKnown
|
|
|
|
local WeakAuras = WeakAuras
|
|
|
|
local spellCache = {}
|
|
WeakAuras.spellCache = spellCache
|
|
|
|
local cache
|
|
local bestIcon = {}
|
|
local dynFrame = WeakAuras.dynFrame
|
|
|
|
-- Builds a cache of name/icon pairs from existing spell data
|
|
-- This is a rather slow operation, so it's only done once, and the result is subsequently saved
|
|
function spellCache.Build(callback)
|
|
if cache then
|
|
local co = coroutine.create(function()
|
|
local id = 0
|
|
local misses = 0
|
|
|
|
while misses < 400 do
|
|
id = id + 1
|
|
local name, _, icon = GetSpellInfo(id)
|
|
|
|
if(icon == 136243) then -- 136243 is the a gear icon, we can ignore those spells
|
|
misses = 0;
|
|
elseif name and name ~= "" then
|
|
cache[name] = cache[name] or {}
|
|
cache[name][id] = icon
|
|
misses = 0
|
|
else
|
|
misses = misses + 1
|
|
end
|
|
|
|
coroutine.yield()
|
|
end
|
|
|
|
if callback then
|
|
callback()
|
|
end
|
|
end)
|
|
dynFrame:AddAction(callback, co)
|
|
else
|
|
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
|
end
|
|
end
|
|
|
|
function spellCache.GetIcon(name)
|
|
if (name == nil) then
|
|
return nil;
|
|
end
|
|
if cache then
|
|
if (bestIcon[name]) then
|
|
return bestIcon[name]
|
|
end
|
|
|
|
local icons = cache[name]
|
|
local bestMatch = nil
|
|
if (icons) then
|
|
for spellId, icon in pairs(icons) do
|
|
if (not bestMatch) then
|
|
bestMatch = spellId
|
|
elseif(type(spellId) == "number" and IsSpellKnown(spellId)) then
|
|
bestMatch = spellId
|
|
end
|
|
end
|
|
end
|
|
|
|
bestIcon[name] = bestMatch and icons[bestMatch];
|
|
return bestIcon[name];
|
|
else
|
|
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
|
end
|
|
end
|
|
|
|
function spellCache.AddIcon(name, id, icon)
|
|
if cache then
|
|
if name then
|
|
cache[name] = cache[name] or {}
|
|
if id and icon then
|
|
cache[name][id] = icon
|
|
end
|
|
end
|
|
else
|
|
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
|
end
|
|
end
|
|
|
|
function spellCache.Get()
|
|
if cache then
|
|
return cache
|
|
else
|
|
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
|
end
|
|
end
|
|
|
|
function spellCache.Load(data)
|
|
cache = cache or data
|
|
end
|
|
|
|
-- This function computes the Levenshtein distance between two strings
|
|
-- It is used in this program to match spell icon textures with "good" spell names; i.e.,
|
|
-- spell names that are very similar to the name of the texture
|
|
local function Lev(str1, str2)
|
|
local matrix = {};
|
|
for i=0, str1:len() do
|
|
matrix[i] = {[0] = i};
|
|
end
|
|
for j=0, str2:len() do
|
|
matrix[0][j] = j;
|
|
end
|
|
for j=1, str2:len() do
|
|
for i =1, str1:len() do
|
|
if(str1:sub(i, i) == str2:sub(j, j)) then
|
|
matrix[i][j] = matrix[i-1][j-1];
|
|
else
|
|
matrix[i][j] = math.min(matrix[i-1][j], matrix[i][j-1], matrix[i-1][j-1]) + 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
return matrix[str1:len()][str2:len()];
|
|
end
|
|
|
|
function spellCache.BestKeyMatch(nearkey)
|
|
local bestKey = "";
|
|
local bestDistance = math.huge;
|
|
local partialMatches = {};
|
|
if cache[nearkey] then
|
|
return nearkey
|
|
end
|
|
for key, value in pairs(cache) do
|
|
if key:lower() == nearkey:lower() then
|
|
return key
|
|
end
|
|
if(key:lower():find(nearkey:lower(), 1, true)) then
|
|
partialMatches[key] = value;
|
|
end
|
|
end
|
|
for key, value in pairs(partialMatches) do
|
|
local distance = Lev(nearkey, key);
|
|
if(distance < bestDistance) then
|
|
bestKey = key;
|
|
bestDistance = distance;
|
|
end
|
|
end
|
|
|
|
return bestKey;
|
|
end
|
|
|
|
function spellCache.CorrectAuraName(input)
|
|
if (not cache) then
|
|
error("spellCache has not been loaded. Call WeakAuras.spellCache.Load(...) first.")
|
|
end
|
|
|
|
local spellId = WeakAuras.SafeToNumber(input);
|
|
if(spellId) then
|
|
local name, _, icon = GetSpellInfo(spellId);
|
|
if(name) then
|
|
spellCache.AddIcon(name, spellId, icon)
|
|
return name, spellId;
|
|
else
|
|
return "Invalid Spell ID";
|
|
end
|
|
else
|
|
local ret = spellCache.BestKeyMatch(input);
|
|
if(ret == "") then
|
|
return "No Match Found", nil;
|
|
else
|
|
return ret, nil;
|
|
end
|
|
end
|
|
end
|