-
Notifications
You must be signed in to change notification settings - Fork 2
/
custom.lua
483 lines (415 loc) · 14.8 KB
/
custom.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
local GetTime = QuestHelper_GetTime
QuestHelper_File["custom.lua"] = "4.3.0.244r"
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
local function searchNPC(input, yield_countdown, yield_countdown_max)
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
return yield_countdown
end
local elders = {
["Alliance"] = {
["Bladeswift"] = "Darnassus 39 32",
["Bronzebeard"] = "Ironforge 29 16",
["Hammershout"] = "Elwynn Forest 34 50"
},
["Horde"] = {
["Darkhorn"] = "Orgrimmar 52 60",
["Wheathoof"] = "Thunder Bluff 72 33",
["Darkcore"] = "Undercity 67 38"
},
["Kalimdor"] = {
["Riversong"] = "Ashenvale 35 48",
["Skygleam"] = "Azshara 64 79",
["High Mountain"] = "Southern Barrens 41 47", -- 41.5 47.5
["Moonwarden"] = "Northern Barrens 48 59", -- 48.5 59.2
["Windtotem"] = "Northern Barrens 68 69",
["Starweave"] = "Darkshore 49 19", -- 49.5 19.0
["Runetotem"] = "Durotar 54 44",
["Nightwind"] = "Felwood 37 52",
["Grimtotem"] = "Feralas 76 37",
["Mistwalker"] = "Feralas 62 31",
["Bloodhoof"] = "Mulgore 48 53",
["Bladesing"] = "Silithus 53 35",
["Primestone"] = "Silithus 30 13", -- 30.7 13.3
["Dreamseer"] = "Tanaris 50 28",
["Ragetotem"] = "Tanaris 36 80",
["Bladeleaf"] = "Teldrassil 57 53",
["Skyseer"] = "Thousand Needles 45 50",
["Morningdew"] = "Thousand Needles 77 75", -- 77.0 75.6
["Thunderhorn"] = "Un'Goro Crater 51 75",
["Brightspear"] = "Winterspring 53 56", -- 53.0 56.7
["Stonespire"] = "Winterspring 60 50", -- 60.0 50.0
},
["Eastern Kingdoms"] = {
["Bellowrage"] = "Blasted Lands 54 49",
["Rumblerock"] = "Burning Steppes 70 45",
["Dawnstrider"] = "Burning Steppes 53 24",
["Goldwell"] = "Dun Morogh 53 49",
["Windrun"] = "Eastern Plaguelands 35 68",
["Snowcrown"] = "Eastern Plaguelands 75 54",
["Stormbrow"] = "Elwynn Forest 40 63",
["Highpeak"] = "Hinterlands 50 48",
["Silvervein"] = "Loch Modan 33 46",
["Ironband"] = "Searing Gorge 21 79",
["Obsidian"] = "Silverpine Forest 45 41",
["Starglade"] = "Stranglethorn Vale 63 22", -- Jungle 71 34
["Winterhoof"] = "Stranglethorn Vale 37 79", -- Cape 39 72
["Graveborn"] = "Tirisfal Glades 61 53",
["Moonstrike"] = "Western Plaguelands 69 73",
["Meadowrun"] = "Western Plaguelands 63 36",
["Skychaser"] = "Westfall 56 47"
},
["Northrend"] = {
["Arp"] = "Borean Tundra 57 44",
["Northal"] = "Borean Tundra 34 34",
["Pamuya"] = "Borean Tundra 43 50",
["Sardis"] = "Borean Tundra 59 66",
["Morthie"] = "Dragonblight 30 56",
["Skywarden"] = "Dragonblight 35 48",
["Thoim"] = "Dragonblight 49 78",
["Beldak"] = "Grizzly Hills 61 28",
["Lunaro"] = "Grizzly Hills 81 37",
["Whurain"] = "Grizzly Hills 64 47",
["Bluewolf"] = "Wintergrasp 49 14",
["Sandrene"] = "Sholazar Basin 50 64",
["Wanikaya"] = "Sholazar Basin 64 49",
["Fargal"] = "Storm Peaks 29 74",
["Graymane"] = "Storm Peaks 41 85",
["Muraco"] = "Storm Peaks 64 51",
["Stonebeard"] = "Storm Peaks 31 38",
["Tauros"] = "Zul'Drak 59 56"
}
}
local function searchItem(input, yield_countdown, yield_countdown_max)
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
return yield_countdown
end
local function searchLoc(input, yield_countdown, yield_countdown_max)
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
return yield_countdown
end
local function searchElders(input, yield_countdown, yield_countdown_max)
local yc = yield_countdown
local achievement_match, elder_match = false, false
for achievement, eldrs in pairs(elders) do
if input and input ~= "" then
if input == string.upper(achievement) then achievement_match = true end
end
for elder, elder_loc in pairs(eldrs) do
if input and input ~= "" then
if achievement_match then -- just add it
yc = searchLoc(string.upper(elder_loc), yc, yield_countdown_max)
elseif input == string.upper(elder) then -- We have input and it's not an achievement, so it must be an elder.
elder_match = true
yc = searchLoc(string.upper(elder_loc), yc, yield_countdown_max)
break -- We've found him or her.
end -- No need for else here. We've got input so we either have an achievement or we have an elder.
else -- We came in without an input, therefore we add all.
yc = searchLoc(string.upper(elder_loc), yc, yield_countdown_max)
end
end
if achievement_match or elder_match then break end -- We've done our match.
end
return yc
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, search_elders = false, false, false, false
local yield_countdown_max = math.max(1, math.floor(2000/string.len(input)+0.5))
local yield_countdown = yield_countdown_max
if command and argument then
if command == "ITEM" then
searchItem(argument, yield_countdown, yield_countdown_max)
elseif command == "NPC" or command == "MONSTER" then
searchNPC(argument, yield_countdown, yield_countdown_max)
elseif command == "LOCATION" or command == "LOC" then
searchLoc(argument, yield_countdown, yield_countdown_max)
elseif command == "ELDER" or command == "ELDERS" then
searchElders(argument, yield_countdown, yield_countdown_max)
else
yield_countdown = searchItem(input, yield_countdown, yield_countdown_max)
yield_countdown = searchNPC(input, yield_countdown, yield_countdown_max)
searchLoc(input, yield_countdown, yield_countdown_max)
end
else
yield_countdown = searchItem(input, yield_countdown, yield_countdown_max)
yield_countdown = searchNPC(input, yield_countdown, yield_countdown_max)
searchLoc(input, yield_countdown, yield_countdown_max)
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