clean up some shit
[QuestHelper.git] / custom.lua
blobe6aa2179915f871beda74aa86cecc4367d3dc61d
1 QuestHelper_File["custom.lua"] = "Development Version"
2 QuestHelper_Loadtime["custom.lua"] = GetTime()
4 do return end
6 -- This next bit of stuff is for fuzzy string comarisons.
9 local row, prow = {}, {}
11 local difftable = {}
13 for i = 65,90 do
14 local a = {}
15 difftable[i-64] = a
16 for j = 65,90 do
17 a[j-64] = i==j and 0 or 1
18 end
19 end
21 local function setgroup(a, w)
22 for i = 1,string.len(a)-1 do
23 for j = i+1,string.len(a) do
24 local c1, c2 = string.byte(a,i)-64, string.byte(a,j)-64
26 difftable[c1][c2] = math.min(w, difftable[c1][c2])
27 difftable[c2][c1] = math.min(w, difftable[c2][c1])
28 end
29 end
30 end
32 -- Characters that sound similar. At least in my opinion.
33 setgroup("BCDFGHJKLMNPQRSTVWXZ", 0.9)
34 setgroup("AEIOUY", 0.6)
35 setgroup("TD", 0.6)
36 setgroup("CKQ", 0.4)
37 setgroup("MN", 0.4)
38 setgroup("EIY", 0.3)
39 setgroup("UO", 0.2)
40 setgroup("SZ", 0.6)
42 local function diffness(a, b)
43 if a >= 65 and a <=90 then
44 if b >= 65 and b <= 90 then
45 return difftable[a-64][b-64]
46 else
47 return 1
48 end
49 elseif b >= 65 and b <= 90 then
50 return 1
51 else
52 return 0
53 end
54 end
56 local function fuzzyCompare(a, b)
57 local m, n = string.len(a), string.len(b)
59 if n == 0 or m == 0 then
60 return n == m and 0 or 1
61 end
63 for j = 1,n+1 do
64 row[j] = j-1
65 end
67 for i = 1,m do
68 row, prow = prow, row
69 row[1] = i
71 for j = 1,n do
72 row[j+1] = math.min(prow[j+1]+1, row[j]+.4, prow[j]+diffness(string.byte(a,i), string.byte(b,j)))
73 end
74 end
76 return row[n+1]/math.max(n,m)
77 end
79 local search_frame = CreateFrame("Button", nil, UIParent)
80 search_frame.text = search_frame:CreateFontString()
81 search_frame.text:SetFont(QuestHelper.font.sans, 15)
82 search_frame.text:SetTextColor(1, 1, 1)
83 search_frame.text:SetJustifyH("CENTER")
84 search_frame.text:SetJustifyV("MIDDLE")
85 search_frame.text:SetDrawLayer("OVERLAY")
86 search_frame.text:SetAllPoints()
87 search_frame.text:Show()
88 search_frame.background = search_frame:CreateTexture()
89 search_frame.background:SetTexture(0, 0, 0, 0.5)
90 search_frame.background:SetDrawLayer("BACKGROUND")
91 search_frame.background:SetAllPoints()
92 search_frame.background:Show()
93 search_frame:SetPoint("CENTER", UIParent, "CENTER")
94 search_frame:Hide()
96 search_frame.results = {}
98 function search_frame:SetText(text)
99 self.text:SetText(text)
100 self:SetWidth(self.text:GetWidth()+10)
101 self:SetHeight(self.text:GetHeight()+10)
104 function search_frame:OnUpdate()
105 if self.routine and coroutine.status(self.routine) ~= "dead" then
106 local no_error, display = coroutine.resume(self.routine, self, self.query)
107 if no_error then
108 self:SetText(display)
109 else
110 QuestHelper:TextOut("Searching co-routine just exploded: "..display)
112 else
113 self:ShowResults()
114 self.routine = nil
115 QH_Hook(self, "OnUpdate", nil)
116 self:Hide()
120 function QuestHelper:ToggleUserObjective(cat, what)
121 local objective = self:GetObjective(cat, what)
123 if self.user_objectives[objective] then
124 self:TextOut(QHFormat("REMOVED_OBJ", self.user_objectives[objective]))
125 self:RemoveObjectiveWatch(objective, self.user_objectives[objective])
126 self.user_objectives[objective] = nil
127 elseif objective:Known() then
128 local name
129 if cat == "loc" then
130 local _, _, i, x, y = string.find(what, "^(%d+),([%d%.]+),([%d%.]+)$")
131 name = QHFormat("USER_OBJ", self:HighlightText(QuestHelper_NameLookup[tonumber(i)])..": "..self:HighlightText(x*100)..", "..self:HighlightText(y*100))
132 else
133 name = QHFormat("USER_OBJ", self:HighlightText(string.gsub(cat, "^(.)", string.upper))..": "..self:HighlightText(what))
136 objective.priority = 1
137 self.user_objectives[objective] = name
138 self:AddObjectiveWatch(objective, name)
140 self:TextOut(QHFormat("CREATED_OBJ", name))
141 else
142 self:TextOut(QHText("UNKNOWN_OBJ"))
146 function search_frame:CreateResultItem(r, menu)
147 local item
149 if r.cat == "loc" then
150 local _, _, i, x, y = string.find(r.what, "^(%d+),([%d%.]+),([%d%.]+)$")
151 item = QuestHelper:CreateMenuItem(menu, QuestHelper_NameLookup[tonumber(i)]..": "..(x*100)..", "..(y*100).." ["..QuestHelper:PercentString(1-r.w).."]")
152 item:AddTexture(QuestHelper:CreateIconTexture(item, 6), true)
153 else
154 item = QuestHelper:CreateMenuItem(menu, r.what .. " ["..QuestHelper:PercentString(1-r.w).."]")
155 item:AddTexture(QuestHelper:CreateIconTexture(item, (r.cat == "monster" and 1) or 2), true)
158 item:SetFunction(QuestHelper.ToggleUserObjective, QuestHelper, r.cat, r.what)
160 return item
163 function search_frame:ShowResults()
164 local menu = QuestHelper:CreateMenu()
165 QuestHelper:CreateMenuTitle(menu, QHText("RESULTS_TITLE"))
167 if #self.results == 0 then
168 QuestHelper:CreateMenuItem(menu, QHText("NO_RESULTS"))
169 else
170 for i, r in ipairs(self.results) do
171 self:CreateResultItem(r, menu)
175 menu:ShowAtCursor()
176 self:ClearResults()
179 function search_frame:ClearResults()
180 while #self.results > 0 do
181 QuestHelper:ReleaseTable(table.remove(self.results))
185 function search_frame:AddResult(cat, what, w)
186 local r = self.results
187 local mn, mx = 1, #r+1
189 while mn ~= mx do
190 local m = math.floor((mn+mx)*0.5)
192 if r[m].w < w then
193 mn = m+1
194 else
195 mx = m
199 if mn <= 20 then
200 if r[mn] and r[mn].cat == cat and r[mn].what == what then
201 -- Don't add the same item twice.
202 -- Might miss it if multiple items have the same score. Dont care.
203 return
206 if #r >= 20 then
207 QuestHelper:ReleaseTable(table.remove(r, 20))
210 local obj = QuestHelper:CreateTable()
211 obj.cat = cat
212 obj.what = what
213 obj.w = w
214 table.insert(r, mn, obj)
218 function search_frame:SearchRoutine(input)
219 if input == "" then
220 for obj in pairs(QuestHelper.user_objectives) do
221 self:AddResult(obj.cat, obj.obj, 0)
223 return
226 input = string.upper(input)
227 local _, _, command, argument = string.find(input, "^%s*([^%s]-)%s+(.-)%s*$")
229 local search_item, search_npc, search_loc = false, false, false
231 if command and argument then
232 if command == "ITEM" then
233 search_item, input = true, argument
234 elseif command == "NPC" or command == "MONSTER" then
235 search_npc, input = true, argument
236 elseif command == "LOCATION" or command == "LOC" then
237 search_loc, input = true, argument
238 else
239 search_item, search_npc, search_loc = true, true, true
241 else
242 search_item, search_npc, search_loc = true, true, true
245 local yield_countdown_max = math.max(1, math.floor(2000/string.len(input)+0.5))
246 local yield_countdown = yield_countdown_max
248 if search_item then
249 local list = QuestHelper_Objectives_Local["item"]
250 if list then for n in pairs(list) do
251 self:AddResult("item", n, fuzzyCompare(input, string.upper(n)))
252 yield_countdown = yield_countdown - 1
253 if yield_countdown == 0 then
254 yield_countdown = yield_countdown_max
255 coroutine.yield(QHFormat("SEARCHING_STATE", QHFormat("SEARCHING_LOCAL", QHText("SEARCHING_ITEMS"))))
257 end end
259 list = QuestHelper_StaticData[QuestHelper.locale].objective
260 list = list and list.item
261 if list then for n in pairs(list) do
262 self:AddResult("item", n, fuzzyCompare(input, string.upper(n)))
263 yield_countdown = yield_countdown - 1
264 if yield_countdown == 0 then
265 yield_countdown = yield_countdown_max
266 coroutine.yield(QHFormat("SEARCHING_STATE", QHFormat("SEARCHING_STATIC", QHText("SEARCHING_ITEMS"))))
268 end end
271 if search_npc then
272 local list = QuestHelper_Objectives_Local["monster"]
273 if list then for n in pairs(list) do
274 self:AddResult("monster", n, fuzzyCompare(input, string.upper(n)))
275 yield_countdown = yield_countdown - 1
276 if yield_countdown == 0 then
277 yield_countdown = yield_countdown_max
278 coroutine.yield(QHFormat("SEARCHING_STATE", QHFormat("SEARCHING_LOCAL", QHText("SEARCHING_NPCS"))))
280 end end
282 list = QuestHelper_StaticData[QuestHelper.locale].objective
283 list = list and list.monster
284 if list then for n in pairs(list) do
285 self:AddResult("monster", n, fuzzyCompare(input, string.upper(n)))
286 yield_countdown = yield_countdown - 1
287 if yield_countdown == 0 then
288 yield_countdown = yield_countdown_max
289 coroutine.yield(QHFormat("SEARCHING_STATE", QHFormat("SEARCHING_STATIC", QHText("SEARCHING_NPCS"))))
291 end end
294 if search_loc then
295 local _, _, region, x, y = string.find(input, "^%s*([^%d%.]-)%s*([%d%.]+)%s*[,;:]?%s*([%d%.]+)%s*$")
297 if region then
298 x, y = tonumber(x), tonumber(y)
299 if x and y then
300 x, y = x*0.01, y*0.01
302 if region == "" then
303 self:AddResult("loc", string.format("%d,%.3f,%.3f", QuestHelper.i, x, y), 0)
304 else
305 for i, name in pairs(QuestHelper_NameLookup) do
306 self:AddResult("loc", string.format("%d,%.3f,%.3f", i, x, y), fuzzyCompare(region, string.upper(name)))
307 yield_countdown = yield_countdown - 1
308 if yield_countdown == 0 then
309 yield_countdown = yield_countdown_max
310 coroutine.yield(QHFormat("SEARCHING_STATE", QHText("SEARCHING_ZONES")))
318 return QHText("SEARCHING_DONE")
321 local function ReturnArgument(x)
322 return x
325 function search_frame:PerformSearch(input)
326 QuestHelper:TextOut("/qh find is currently disabled. Sorry! I'll get it back in once I can.")
327 do return end
328 if not self.routine then
329 self.query = string.gsub(input, "|c.-|H.-|h%[(.-)%]|h|r", ReturnArgument)
330 self.routine = coroutine.create(self.SearchRoutine)
331 self:Show()
332 QH_Hook(self, "OnUpdate", self.OnUpdate)
336 function QuestHelper:PerformSearch(query)
337 search_frame:PerformSearch(query)
340 function QuestHelper:PerformCustomSearch(func)
341 if not search_frame:GetScript("OnUpdate") then
342 search_frame:Show()
343 QH_Hook(search_frame, "OnUpdate", func)
347 function QuestHelper:StopCustomSearch()
348 if not search_frame.routine then
349 search_frame:Hide()
350 QH_Hook(search_frame, "OnUpdate", nil)
354 SLASH_QuestHelperFind1 = "/qhfind"
355 SLASH_QuestHelperFind2 = "/find"
356 SlashCmdList["QuestHelperFind"] = function (text) QuestHelper:PerformSearch(text) end