358 lignes
10 Kio
Lua
358 lignes
10 Kio
Lua
|
QuestHelper_File["custom.lua"] = "1.4.0"
|
||
|
QuestHelper_Loadtime["custom.lua"] = GetTime()
|
||
|
|
||
|
local search_frame = CreateFrame("Button", nil, UIParent)
|
||
|
search_frame.text = search_frame:CreateFontString()
|
||
|
search_frame.text:SetFont(QuestHelper.font.sans, 15)
|
||
|
search_frame.text:SetTextColor(1, 1, 1)
|
||
|
search_frame.text:SetJustifyH("CENTER")
|
||
|
search_frame.text:SetJustifyV("MIDDLE")
|
||
|
search_frame.text:SetDrawLayer("OVERLAY")
|
||
|
search_frame.text:SetAllPoints()
|
||
|
search_frame.text:Show()
|
||
|
search_frame.background = search_frame:CreateTexture()
|
||
|
search_frame.background:SetTexture(0, 0, 0, 0.5)
|
||
|
search_frame.background:SetDrawLayer("BACKGROUND")
|
||
|
search_frame.background:SetAllPoints()
|
||
|
search_frame.background:Show()
|
||
|
search_frame:SetPoint("CENTER", UIParent, "CENTER")
|
||
|
search_frame:Hide()
|
||
|
|
||
|
search_frame.results = {}
|
||
|
|
||
|
function search_frame:SetText(text)
|
||
|
self.text:SetText(text)
|
||
|
self:SetWidth(self.text:GetWidth()+10)
|
||
|
self:SetHeight(self.text:GetHeight()+10)
|
||
|
end
|
||
|
|
||
|
function search_frame:OnUpdate()
|
||
|
if self.routine and coroutine.status(self.routine) ~= "dead" then
|
||
|
local no_error, display = coroutine.resume(self.routine, self, self.query)
|
||
|
if no_error then
|
||
|
self:SetText(display)
|
||
|
else
|
||
|
QuestHelper:TextOut("Searching co-routine just exploded: "..display)
|
||
|
end
|
||
|
else
|
||
|
self:ShowResults()
|
||
|
self.routine = nil
|
||
|
QH_Hook(self, "OnUpdate", nil)
|
||
|
self:Hide()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function QuestHelper:PerformCustomSearch(func)
|
||
|
if not search_frame:GetScript("OnUpdate") then
|
||
|
search_frame:Show()
|
||
|
QH_Hook(search_frame, "OnUpdate", func)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function QuestHelper:StopCustomSearch()
|
||
|
if not search_frame.routine then
|
||
|
search_frame:Hide()
|
||
|
QH_Hook(search_frame, "OnUpdate", nil)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
do return end
|
||
|
|
||
|
-- This next bit of stuff is for fuzzy string comarisons.
|
||
|
|
||
|
|
||
|
local row, prow = {}, {}
|
||
|
|
||
|
local difftable = {}
|
||
|
|
||
|
for i = 65,90 do
|
||
|
local a = {}
|
||
|
difftable[i-64] = a
|
||
|
for j = 65,90 do
|
||
|
a[j-64] = i==j and 0 or 1
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function setgroup(a, w)
|
||
|
for i = 1,string.len(a)-1 do
|
||
|
for j = i+1,string.len(a) do
|
||
|
local c1, c2 = string.byte(a,i)-64, string.byte(a,j)-64
|
||
|
|
||
|
difftable[c1][c2] = math.min(w, difftable[c1][c2])
|
||
|
difftable[c2][c1] = math.min(w, difftable[c2][c1])
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Characters that sound similar. At least in my opinion.
|
||
|
setgroup("BCDFGHJKLMNPQRSTVWXZ", 0.9)
|
||
|
setgroup("AEIOUY", 0.6)
|
||
|
setgroup("TD", 0.6)
|
||
|
setgroup("CKQ", 0.4)
|
||
|
setgroup("MN", 0.4)
|
||
|
setgroup("EIY", 0.3)
|
||
|
setgroup("UO", 0.2)
|
||
|
setgroup("SZ", 0.6)
|
||
|
|
||
|
local function diffness(a, b)
|
||
|
if a >= 65 and a <=90 then
|
||
|
if b >= 65 and b <= 90 then
|
||
|
return difftable[a-64][b-64]
|
||
|
else
|
||
|
return 1
|
||
|
end
|
||
|
elseif b >= 65 and b <= 90 then
|
||
|
return 1
|
||
|
else
|
||
|
return 0
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function fuzzyCompare(a, b)
|
||
|
local m, n = string.len(a), string.len(b)
|
||
|
|
||
|
if n == 0 or m == 0 then
|
||
|
return n == m and 0 or 1
|
||
|
end
|
||
|
|
||
|
for j = 1,n+1 do
|
||
|
row[j] = j-1
|
||
|
end
|
||
|
|
||
|
for i = 1,m do
|
||
|
row, prow = prow, row
|
||
|
row[1] = i
|
||
|
|
||
|
for j = 1,n do
|
||
|
row[j+1] = math.min(prow[j+1]+1, row[j]+.4, prow[j]+diffness(string.byte(a,i), string.byte(b,j)))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return row[n+1]/math.max(n,m)
|
||
|
end
|
||
|
|
||
|
function QuestHelper:ToggleUserObjective(cat, what)
|
||
|
local objective = self:GetObjective(cat, what)
|
||
|
|
||
|
if self.user_objectives[objective] then
|
||
|
self:TextOut(QHFormat("REMOVED_OBJ", self.user_objectives[objective]))
|
||
|
self:RemoveObjectiveWatch(objective, self.user_objectives[objective])
|
||
|
self.user_objectives[objective] = nil
|
||
|
elseif objective:Known() then
|
||
|
local name
|
||
|
if cat == "loc" then
|
||
|
local _, _, i, x, y = string.find(what, "^(%d+),([%d%.]+),([%d%.]+)$")
|
||
|
name = QHFormat("USER_OBJ", self:HighlightText(QuestHelper_NameLookup[tonumber(i)])..": "..self:HighlightText(x*100)..", "..self:HighlightText(y*100))
|
||
|
else
|
||
|
name = QHFormat("USER_OBJ", self:HighlightText(string.gsub(cat, "^(.)", string.upper))..": "..self:HighlightText(what))
|
||
|
end
|
||
|
|
||
|
objective.priority = 1
|
||
|
self.user_objectives[objective] = name
|
||
|
self:AddObjectiveWatch(objective, name)
|
||
|
|
||
|
self:TextOut(QHFormat("CREATED_OBJ", name))
|
||
|
else
|
||
|
self:TextOut(QHText("UNKNOWN_OBJ"))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function search_frame:CreateResultItem(r, menu)
|
||
|
local item
|
||
|
|
||
|
if r.cat == "loc" then
|
||
|
local _, _, i, x, y = string.find(r.what, "^(%d+),([%d%.]+),([%d%.]+)$")
|
||
|
item = QuestHelper:CreateMenuItem(menu, QuestHelper_NameLookup[tonumber(i)]..": "..(x*100)..", "..(y*100).." ["..QuestHelper:PercentString(1-r.w).."]")
|
||
|
item:AddTexture(QuestHelper:CreateIconTexture(item, 6), true)
|
||
|
else
|
||
|
item = QuestHelper:CreateMenuItem(menu, r.what .. " ["..QuestHelper:PercentString(1-r.w).."]")
|
||
|
item:AddTexture(QuestHelper:CreateIconTexture(item, (r.cat == "monster" and 1) or 2), true)
|
||
|
end
|
||
|
|
||
|
item:SetFunction(QuestHelper.ToggleUserObjective, QuestHelper, r.cat, r.what)
|
||
|
|
||
|
return item
|
||
|
end
|
||
|
|
||
|
function search_frame:ShowResults()
|
||
|
local menu = QuestHelper:CreateMenu()
|
||
|
QuestHelper:CreateMenuTitle(menu, QHText("RESULTS_TITLE"))
|
||
|
|
||
|
if #self.results == 0 then
|
||
|
QuestHelper:CreateMenuItem(menu, QHText("NO_RESULTS"))
|
||
|
else
|
||
|
for i, r in ipairs(self.results) do
|
||
|
self:CreateResultItem(r, menu)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
menu:ShowAtCursor()
|
||
|
self:ClearResults()
|
||
|
end
|
||
|
|
||
|
function search_frame:ClearResults()
|
||
|
while #self.results > 0 do
|
||
|
QuestHelper:ReleaseTable(table.remove(self.results))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function search_frame:AddResult(cat, what, w)
|
||
|
local r = self.results
|
||
|
local mn, mx = 1, #r+1
|
||
|
|
||
|
while mn ~= mx do
|
||
|
local m = math.floor((mn+mx)*0.5)
|
||
|
|
||
|
if r[m].w < w then
|
||
|
mn = m+1
|
||
|
else
|
||
|
mx = m
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if mn <= 20 then
|
||
|
if r[mn] and r[mn].cat == cat and r[mn].what == what then
|
||
|
-- Don't add the same item twice.
|
||
|
-- Might miss it if multiple items have the same score. Dont care.
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if #r >= 20 then
|
||
|
QuestHelper:ReleaseTable(table.remove(r, 20))
|
||
|
end
|
||
|
|
||
|
local obj = QuestHelper:CreateTable()
|
||
|
obj.cat = cat
|
||
|
obj.what = what
|
||
|
obj.w = w
|
||
|
table.insert(r, mn, obj)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function search_frame:SearchRoutine(input)
|
||
|
if input == "" then
|
||
|
for obj in pairs(QuestHelper.user_objectives) do
|
||
|
self:AddResult(obj.cat, obj.obj, 0)
|
||
|
end
|
||
|
return
|
||
|
end
|
||
|
|
||
|
input = string.upper(input)
|
||
|
local _, _, command, argument = string.find(input, "^%s*([^%s]-)%s+(.-)%s*$")
|
||
|
|
||
|
local search_item, search_npc, search_loc = false, false, false
|
||
|
|
||
|
if command and argument then
|
||
|
if command == "ITEM" then
|
||
|
search_item, input = true, argument
|
||
|
elseif command == "NPC" or command == "MONSTER" then
|
||
|
search_npc, input = true, argument
|
||
|
elseif command == "LOCATION" or command == "LOC" then
|
||
|
search_loc, input = true, argument
|
||
|
else
|
||
|
search_item, search_npc, search_loc = true, true, true
|
||
|
end
|
||
|
else
|
||
|
search_item, search_npc, search_loc = true, true, true
|
||
|
end
|
||
|
|
||
|
local yield_countdown_max = math.max(1, math.floor(2000/string.len(input)+0.5))
|
||
|
local yield_countdown = yield_countdown_max
|
||
|
|
||
|
if search_item then
|
||
|
local list = QuestHelper_Objectives_Local["item"]
|
||
|
if list then for n in pairs(list) do
|
||
|
self:AddResult("item", n, fuzzyCompare(input, string.upper(n)))
|
||
|
yield_countdown = yield_countdown - 1
|
||
|
if yield_countdown == 0 then
|
||
|
yield_countdown = yield_countdown_max
|
||
|
coroutine.yield(QHFormat("SEARCHING_STATE", QHFormat("SEARCHING_LOCAL", QHText("SEARCHING_ITEMS"))))
|
||
|
end
|
||
|
end end
|
||
|
|
||
|
list = QuestHelper_StaticData[QuestHelper.locale].objective
|
||
|
list = list and list.item
|
||
|
if list then for n in pairs(list) do
|
||
|
self:AddResult("item", n, fuzzyCompare(input, string.upper(n)))
|
||
|
yield_countdown = yield_countdown - 1
|
||
|
if yield_countdown == 0 then
|
||
|
yield_countdown = yield_countdown_max
|
||
|
coroutine.yield(QHFormat("SEARCHING_STATE", QHFormat("SEARCHING_STATIC", QHText("SEARCHING_ITEMS"))))
|
||
|
end
|
||
|
end end
|
||
|
end
|
||
|
|
||
|
if search_npc then
|
||
|
local list = QuestHelper_Objectives_Local["monster"]
|
||
|
if list then for n in pairs(list) do
|
||
|
self:AddResult("monster", n, fuzzyCompare(input, string.upper(n)))
|
||
|
yield_countdown = yield_countdown - 1
|
||
|
if yield_countdown == 0 then
|
||
|
yield_countdown = yield_countdown_max
|
||
|
coroutine.yield(QHFormat("SEARCHING_STATE", QHFormat("SEARCHING_LOCAL", QHText("SEARCHING_NPCS"))))
|
||
|
end
|
||
|
end end
|
||
|
|
||
|
list = QuestHelper_StaticData[QuestHelper.locale].objective
|
||
|
list = list and list.monster
|
||
|
if list then for n in pairs(list) do
|
||
|
self:AddResult("monster", n, fuzzyCompare(input, string.upper(n)))
|
||
|
yield_countdown = yield_countdown - 1
|
||
|
if yield_countdown == 0 then
|
||
|
yield_countdown = yield_countdown_max
|
||
|
coroutine.yield(QHFormat("SEARCHING_STATE", QHFormat("SEARCHING_STATIC", QHText("SEARCHING_NPCS"))))
|
||
|
end
|
||
|
end end
|
||
|
end
|
||
|
|
||
|
if search_loc then
|
||
|
local _, _, region, x, y = string.find(input, "^%s*([^%d%.]-)%s*([%d%.]+)%s*[,;:]?%s*([%d%.]+)%s*$")
|
||
|
|
||
|
if region then
|
||
|
x, y = tonumber(x), tonumber(y)
|
||
|
if x and y then
|
||
|
x, y = x*0.01, y*0.01
|
||
|
|
||
|
if region == "" then
|
||
|
self:AddResult("loc", string.format("%d,%.3f,%.3f", QuestHelper.i, x, y), 0)
|
||
|
else
|
||
|
for i, name in pairs(QuestHelper_NameLookup) do
|
||
|
self:AddResult("loc", string.format("%d,%.3f,%.3f", i, x, y), fuzzyCompare(region, string.upper(name)))
|
||
|
yield_countdown = yield_countdown - 1
|
||
|
if yield_countdown == 0 then
|
||
|
yield_countdown = yield_countdown_max
|
||
|
coroutine.yield(QHFormat("SEARCHING_STATE", QHText("SEARCHING_ZONES")))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return QHText("SEARCHING_DONE")
|
||
|
end
|
||
|
|
||
|
local function ReturnArgument(x)
|
||
|
return x
|
||
|
end
|
||
|
|
||
|
function search_frame:PerformSearch(input)
|
||
|
QuestHelper:TextOut("/qh find is currently disabled. Sorry! I'll get it back in once I can.")
|
||
|
do return end
|
||
|
if not self.routine then
|
||
|
self.query = string.gsub(input, "|c.-|H.-|h%[(.-)%]|h|r", ReturnArgument)
|
||
|
self.routine = coroutine.create(self.SearchRoutine)
|
||
|
self:Show()
|
||
|
QH_Hook(self, "OnUpdate", self.OnUpdate)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function QuestHelper:PerformSearch(query)
|
||
|
search_frame:PerformSearch(query)
|
||
|
end
|
||
|
|
||
|
SLASH_QuestHelperFind1 = "/qhfind"
|
||
|
SLASH_QuestHelperFind2 = "/find"
|
||
|
SlashCmdList["QuestHelperFind"] = function (text) QuestHelper:PerformSearch(text) end
|