2010-11-08 14:28:59 +01:00
QuestHelper_File [ " custom.lua " ] = " 4.0.1.$svnversion$ "
2010-10-24 23:17:33 +02:00
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
2011-01-23 23:45:14 +01:00
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 ) ) )
2010-10-24 23:17:33 +02:00
yield_countdown = yield_countdown - 1
if yield_countdown == 0 then
yield_countdown = yield_countdown_max
2011-01-23 23:45:14 +01:00
coroutine.yield ( QHFormat ( " SEARCHING_STATE " , QHFormat ( " SEARCHING_LOCAL " , QHText ( " SEARCHING_NPCS " ) ) ) )
2010-10-24 23:17:33 +02:00
end
2011-01-23 23:45:14 +01:00
end
end
2010-10-24 23:17:33 +02:00
2011-01-23 23:45:14 +01:00
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 ) ) )
2010-10-24 23:17:33 +02:00
yield_countdown = yield_countdown - 1
if yield_countdown == 0 then
yield_countdown = yield_countdown_max
2011-01-23 23:45:14 +01:00
coroutine.yield ( QHFormat ( " SEARCHING_STATE " , QHFormat ( " SEARCHING_STATIC " , QHText ( " SEARCHING_NPCS " ) ) ) )
2010-10-24 23:17:33 +02:00
end
2011-01-23 23:45:14 +01:00
end
2010-10-24 23:17:33 +02:00
end
2011-01-23 23:45:14 +01:00
return yield_countdown
end
local elders = {
[ " Alliance " ] = {
2011-01-23 23:57:08 +01:00
[ " Bladeswift " ] = " Darnassus 39 32 " ,
[ " Bronzebeard " ] = " Ironforge 29 16 " ,
2011-01-23 23:45:14 +01:00
[ " 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 " ,
2011-01-24 02:45:40 +01:00
[ " Bluewolf " ] = " Wintergrasp 49 14 " ,
2011-01-23 23:45:14 +01:00
[ " 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 ) ) )
2010-10-24 23:17:33 +02:00
yield_countdown = yield_countdown - 1
if yield_countdown == 0 then
yield_countdown = yield_countdown_max
2011-01-23 23:45:14 +01:00
coroutine.yield ( QHFormat ( " SEARCHING_STATE " , QHFormat ( " SEARCHING_LOCAL " , QHText ( " SEARCHING_ITEMS " ) ) ) )
2010-10-24 23:17:33 +02:00
end
2011-01-23 23:45:14 +01:00
end
end
2010-10-24 23:17:33 +02:00
2011-01-23 23:45:14 +01:00
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 ) ) )
2010-10-24 23:17:33 +02:00
yield_countdown = yield_countdown - 1
if yield_countdown == 0 then
yield_countdown = yield_countdown_max
2011-01-23 23:45:14 +01:00
coroutine.yield ( QHFormat ( " SEARCHING_STATE " , QHFormat ( " SEARCHING_STATIC " , QHText ( " SEARCHING_ITEMS " ) ) ) )
2010-10-24 23:17:33 +02:00
end
2011-01-23 23:45:14 +01:00
end
2010-10-24 23:17:33 +02:00
end
2011-01-23 23:45:14 +01:00
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*$ " )
2010-10-24 23:17:33 +02:00
2011-01-23 23:45:14 +01:00
if region then
x , y = tonumber ( x ) , tonumber ( y )
if x and y then
x , y = x * 0.01 , y * 0.01
2010-10-24 23:17:33 +02:00
2011-01-23 23:45:14 +01:00
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 " ) ) )
2010-10-24 23:17:33 +02:00
end
end
end
end
end
2011-01-23 23:45:14 +01:00
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
2011-01-23 23:57:08 +01:00
if input == string.upper ( achievement ) then achievement_match = true end
2011-01-23 23:45:14 +01:00
end
for elder , elder_loc in pairs ( eldrs ) do
if input and input ~= " " then
if achievement_match then -- just add it
2011-01-23 23:57:08 +01:00
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.
2011-01-23 23:45:14 +01:00
elder_match = true
2011-01-23 23:57:08 +01:00
yc = searchLoc ( string.upper ( elder_loc ) , yc , yield_countdown_max )
2011-01-23 23:45:14 +01:00
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.
2011-01-23 23:57:08 +01:00
yc = searchLoc ( string.upper ( elder_loc ) , yc , yield_countdown_max )
2011-01-23 23:45:14 +01:00
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
2010-10-24 23:17:33 +02:00
2011-01-23 23:45:14 +01:00
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
2010-10-24 23:17:33 +02:00
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