1 QuestHelper_File
["utility.lua"] = "Development Version"
2 QuestHelper_Loadtime
["utility.lua"] = GetTime()
4 QuestHelper
= CreateFrame("Frame", "QuestHelper", nil)
6 local default_colour_theme
=
7 {message_prefix
={0.4, 0.78, 1},
10 message_highlight
={0.73, 1, 0.84},
12 menu_text_highlight
={0, 0, 0},
14 menu_highlight
={0.3, 0.5, 0.7},
15 menu_title_text
={1, 1, 1},
16 menu_title_text_highlight
={1, 1, 1},
17 menu_title
={0, 0.2, 0.6},
18 menu_title_highlight
={0.1, 0.4, 0.8}}
20 local xmas_colour_theme
=
21 {message_prefix
={0.0, 0.7, 0.0},
22 message
={0.2, 1, 0.2},
23 tooltip
={0.4, 1, 0.4},
24 message_highlight
={1, 0.3, 0.1},
26 menu_text_highlight
={0, 0, 0},
28 menu_highlight
={1, 0.3, 0.3},
29 menu_title_text
={0.8, 1, 0.8},
30 menu_title_text_highlight
={1, 1, 1},
31 menu_title
={0.2, 0.6, 0.2},
32 menu_title_highlight
={0.4, 0.7, 0.4}}
34 function QuestHelper
:GetColourTheme()
35 if date("%b%d") == "Dec25" then
36 return xmas_colour_theme
39 return default_colour_theme
42 QuestHelper
.nop
= function () end -- Who wouldn't want a function that does nothing?
44 function QuestHelper
:HashString(text
)
45 -- Computes an Adler-32 checksum.
47 for i
=1,string.len(text
) do
48 a
= (a
+string.byte(text
,i
))%65521
54 function QuestHelper
:CreateUID(length
)
56 local characters
= "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
57 for k
= 1, (math
.floor(GetTime() % 1000) + 5) do math
.random() end -- it's sort of like seeding. only worse.
58 local base
= GetUnitName("player")..":"..GetRealmName()..":"..math
.random(0, 2147483647)..":"..GetTime()..":"..time()
60 for c
= 1,(length
or 32) do
61 local pos
= 1+math
.floor(self
:HashString(result
..base
..math
.random(0, 2147483647))%string.len(characters
))
62 result
= result
.. string.sub(characters
, pos
, pos
)
68 function QuestHelper
:ZoneSanity()
71 for c
in pairs(self
.Astrolabe
:GetMapVirtualContinents()) do
72 local pz
= self
.Astrolabe
:GetMapVirtualZones(c
)
78 name
= self
.Astrolabe
:GetMapVirtualContinents()[c
]
80 name
= self
.Astrolabe
:GetMapVirtualZones(c
)[z
]
85 if QuestHelper_Zones
[c
][z
] ~= name
then
87 QuestHelper
:TextOut(string.format("'%s' has the wrong ID (should be %d,%d).", name
, c
, z
))
90 local pair
= QuestHelper_ZoneLookup
[name
]
92 if not pair
or c
~= pair
[1] or z
~= pair
[2] then
94 QuestHelper
:TextOut("ZoneLookup['"..name
.."'] maps to wrong pair.")
97 local index
= QuestHelper_IndexLookup
[name
]
98 if QuestHelper_ZoneLookup
[index
] ~= pair
then
100 QuestHelper
:TextOut("ZoneLookup['"..name
.."'] isn't equal to ZoneLookup["..index
.."]")
103 if not index
or QuestHelper_NameLookup
[index
] ~= name
then
105 QuestHelper
:TextOut("NameLookup["..(index
or "???").."'] doesn't equal '"..name
.."'")
113 function QuestHelper
:TextOut(text
)
114 local theme
= self
:GetColourTheme()
115 DEFAULT_CHAT_FRAME
:AddMessage(string.format("|cff%2x%2x%2xQuestHelper: |r%s", theme
.message_prefix
[1]*255,
116 theme
.message_prefix
[2]*255,
117 theme
.message_prefix
[3]*255, text
),
123 function QuestHelper
:Error(what
)
124 --DEFAULT_CHAT_FRAME:AddMessage("QuestHelper Error: "..(what or "Unknown").."\n"..debugstack(2), 1,.5,0)
125 QuestHelper_ErrorCatcher_ExplicitError(true, what
or "Unknown", nil, nil)
129 function QuestHelper
:HighlightText(text
)
130 local theme
= self
:GetColourTheme()
131 return string.format("|cff%2x%2x%2x%s|r", theme
.message_highlight
[1]*255,
132 theme
.message_highlight
[2]*255,
133 theme
.message_highlight
[3]*255, text
)
136 function QuestHelper
:GetUnitID(unit
)
137 local id
= UnitGUID(unit
)
140 return (string.sub(id
, 5, 5) == "3") and tonumber(string.sub(id
, 6, 12), 16) or nil
146 function QuestHelper
:GetQuestID(index
)
147 return tonumber(select(3, string.find(GetQuestLink(index
), "|Hquest:(%d+):")))
150 -- For future reference:
151 -- Hearthstone = 6948
152 -- Rune of Teleportation = 17031
153 -- Rune of Portals = 17032
155 function QuestHelper
:CountItem(item_id
)
158 for bag
= 0,NUM_BAG_SLOTS
do
159 for slot
= 1,GetContainerNumSlots(bag
) do
160 local link
= GetContainerItemLink(bag
, slot
)
161 if link
and string.find(link
, string.format("|Hitem:%d:", item_id
)) then
162 count
= count
+ (select(2, GetContainerItemInfo(bag
, slot
)) or 0)
170 function QuestHelper
:ItemCooldown(item_id
)
171 local now
= GetTime()
174 for bag
= 0,NUM_BAG_SLOTS
do
175 for slot
= 1,GetContainerNumSlots(bag
) do
176 local link
= GetContainerItemLink(bag
, slot
)
177 if link
and string.find(link
, string.format("|Hitem:%d:", item_id
)) then
178 local s
, d
, e
= GetContainerItemCooldown(bag
, slot
)
181 cooldown
= math
.min(cooldown
, math
.max(0, d
-now
+s
))
183 cooldown
= math
.max(0, d
-now
+s
)
195 function QuestHelper
:TimeString(seconds
)
197 --self:AppendNotificationError("2008-10-8 nil-timestring") -- we're just going to do away with this entirely, the fact is that a lot of this is going to be ripped to shreds soon anyway
201 local seconds
= math
.ceil(seconds
)
202 local h
, m
, s
= math
.floor(seconds
/(60*60)), math
.floor(seconds
/60)%60, seconds
%60
204 return string.format("|cffffffff%d|r:|cffffffff%02d|r:|cffffffff%02d|r", h
, m
, s
)
206 return string.format("|cffffffff%d|r:|cffffffff%02d|r", m
, s
)
210 function QuestHelper
:ProgressString(str
, pct
)
212 return string.format("|cff00ff00%s|r", str
)
214 return string.format("|cffff0000%s|r", str
)
215 elseif pct
> 0.5 then
216 return string.format("|cff%2xff00%s|r", 510-pct
*510, str
)
218 return string.format("|cffff%2x00%s|r", pct
*510, str
)
222 function QuestHelper
:PercentString(pct
)
224 return string.format("|cff00ff00%.1f%%|r", pct
*100)
226 return string.format("|cffff0000%.1f%%|r", pct
*100)
227 elseif pct
> 0.5 then
228 return string.format("|cff%2xff00%.1f%%|r", 510-pct
*510, pct
*100)
230 return string.format("|cffff%2x00%.1f%%|r", pct
*510, pct
*100)
234 function QuestHelper
:PlayerPosition()
235 return self
.i
, self
.x
, self
.y
238 function QuestHelper
:UnitPosition(unit
)
239 local c
, z
, x
, y
= self
.Astrolabe
:GetUnitPosition(unit
,true)
242 SetMapToCurrentZone()
243 z
= GetCurrentMapZone()
245 x
, y
= self
.Astrolabe
:TranslateWorldMapPosition(c
, 0, x
, y
, c
, z
)
248 return QuestHelper_IndexLookup
[c
][z
], x
, y
250 return self
:PlayerPosition()
254 function QuestHelper
:PlayerFaction()
255 return UnitFactionGroup("player") == "Alliance" and 1 or 2
258 function QuestHelper
:LocationString(i
, x
, y
)
259 return ("[|cffffffff%s|r:|cffffffff%d,%.3f,%.3f|r]"):format(QuestHelper_NameLookup
[i
] or "nil", i
or -7777, x
or -7777, y
or -7777)
261 function QuestHelper
:Location_RawString(delayed
, c
, z
, x
, y
)
262 return ("[|cffffffff%s/%s,%s,%s,%s|r]"):format(delayed
and "D" or "c", c
and string.format("%d", c
) or tostring(c
), z
and string.format("%d", z
) or tostring(z
), x
and string.format("%.3f", x
) or tostring(x
), y
and string.format("%.3f", y
) or tostring(y
))
264 function QuestHelper
:Location_AbsoluteString(delayed
, c
, x
, y
)
265 return ("[|cffffffff%s/%s,%s,%s|r]"):format(delayed
and "D" or "c", c
and string.format("%d", c
) or tostring(c
), x
and string.format("%.3f", x
) or tostring(x
), y
and string.format("%.3f", y
) or tostring(y
))
268 function QuestHelper
:Distance(i1
, x1
, y1
, i2
, x2
, y2
)
269 local p1
, p2
= QuestHelper_ZoneLookup
[i1
], QuestHelper_ZoneLookup
[i2
]
270 return self
.Astrolabe
:ComputeDistance(p1
[1], p1
[2], x1
, y1
, p2
[1], p2
[2], x2
, y2
) or 10000
273 function QuestHelper
:AppendPosition(list
, index
, x
, y
, w
, min_dist
)
274 if not x
or not y
or (x
== 0 and y
== 0) or x
<= -0.1 or y
<= -0.1 or x
>= 1.1 or y
>= 1.1 then
275 local nc
, nz
, nx
, ny
= self
.Astrolabe
:GetCurrentPlayerPosition()
276 --self:AppendNotificationError("2008-10-6 nil-position", string.format("nilposition, %s %s %s %s vs %s %s", tostring(nc), tostring(nz), tostring(nx), tostring(ny), tostring(x), tostring(y))) -- We're just not worrying about this too much anymore. Slash and burn.
277 return list
-- This isn't a real position.
280 local closest
, distance
= nil, 0
282 min_dist
= min_dist
or 200
284 for i
, p
in ipairs(list
) do
285 if index
== p
[1] then
286 local d
= self
:Distance(index
, x
, y
, p
[1], p
[2], p
[3])
287 if not closest
or d
< distance
then
288 closest
, distance
= i
, d
293 if closest
and distance
< min_dist
then
294 local p
= list
[closest
]
295 p
[2] = (p
[2]*p
[4]+x
*w
)/(p
[4]+w
)
296 p
[3] = (p
[3]*p
[4]+y
*w
)/(p
[4]+w
)
299 table.insert(list
, {index
, x
, y
, w
})
305 function QuestHelper
:PositionListDistance(list
, index
, x
, y
)
306 local closest
, distance
= nil, 0
307 for i
, p
in ipairs(list
) do
308 local d
= self
:Distance(index
, x
, y
, p
[1], p
[2], p
[3])
309 if not closest
or d
< distance
then
310 closest
, distance
= p
, d
314 return distance
, closest
[1], closest
[2], closest
[3]
318 function QuestHelper
:PositionListDistance2(list
, i1
, x1
, y1
, i2
, x2
, y2
)
319 local closest
, bd1
, bd2
, bdt
= nil, 0, 0, 0
320 for i
, p
in ipairs(list
) do
321 local d1
= self
:Distance(i1
, x1
, y1
, p
[1], p
[2], p
[3])
322 local d2
= self
:Distance(i2
, x2
, y2
, p
[1], p
[2], p
[3])
324 if not closest
or t
< bdt
then
325 closest
, bd1
, bd2
, bdt
= p
, d1
, d2
, t
329 return d1
, d2
, closest
[1], closest
[2], closest
[3]
333 function QuestHelper
:MergePositions(list1
, list2
)
334 for i
, p
in ipairs(list2
) do
335 self
:AppendPosition(list1
, unpack(p
))
339 function QuestHelper
:MergeDrops(list1
, list2
)
340 for element
, count
in pairs(list2
) do
341 list1
[element
] = (list1
[element
] or 0) + count
345 function QuestHelper
: Assert(a
, b
) -- the space exists so the anti-assert script doesn't find it :D
347 QuestHelper
:Error(b
or "Assertion Failed")
351 function QuestHelper
:StringizeTable(a
)
352 if not a
then return "nil" end
353 acu
= tostring(self
.recycle_tabletyping
[a
])..": "
354 for i
,v
in pairs(a
) do acu
= acu
.."["..tostring(i
)..","..tostring(v
).."] " end
358 function QuestHelper
:StringizeTableDouble(a
)
359 if not a
then return "nil" end
360 acu
= tostring(self
.recycle_tabletyping
[a
])..": "
361 for i
,v
in pairs(a
) do acu
= acu
.."["..self
:StringizeTable(i
)..","..self
:StringizeTable(v
).."] " end
365 function QuestHelper
:StringizeRecursive(a
, d
)
366 if not a
then return "nil" end
367 if d
<= 0 or type(a
) ~= "table" then return tostring(a
) end
368 acu
= tostring(self
.recycle_tabletyping
[a
])..": "
369 for i
,v
in pairs(a
) do acu
= acu
.."["..self
:StringizeRecursive(i
, d
- 1)..","..self
:StringizeRecursive(v
, d
- 1).."] " end
373 function QuestHelper
:TableSize(tbl
)
375 for k
, v
in pairs(tbl
) do
381 function QuestHelper
:IsWrath()
382 --return GetBuildInfo():sub(1,1) == '3' or GetBuildInfo() == "0.0.2" -- come on
383 return true -- this had better be true :D
386 function QuestHelper
:IsWrath32()
387 return tonumber(GetBuildInfo():sub(3,3)) >= 2
390 function QuestHelper
:AppendNotificationError(type, data
)
391 local terror
= QuestHelper_ErrorPackage(2)
393 QuestHelper_ErrorCatcher_RegisterError(type, terror
)
398 function QuestHelper
.CreateLoadingCounter()
400 MakeSubcategory
= function(self
, weight
)
401 QuestHelper
: Assert(not self
.percentage
)
402 if not self
.weighting
then self
.weighting
= {} end
403 local subcat
= QuestHelper
:CreateLoadingCounter()
404 table.insert(self
.weighting
, {weight
= weight
, item
= subcat
})
407 SetPercentage
= function(self
, percent
)
408 QuestHelper
: Assert(not self
.weighting
)
409 self
.percentage
= percent
411 GetPercentage
= function(self
)
412 if self
.percentage
then return self
.percentage
end
413 if not self
.weighting
then return 0 end
414 local total_weight
= 0
415 local total_value
= 0
416 for _
, v
in ipairs(self
.weighting
) do
417 total_weight
= total_weight
+ v
.weight
418 total_value
= total_value
+ v
.weight
* v
.item
:GetPercentage()
420 return total_value
/ total_weight
426 function QH_fixedmessage(text
)
427 local msgtext
= "QH_MSG_" .. msgid
428 StaticPopupDialogs
[msgtext
] = {
431 OnAccept
= function(self
)
438 StaticPopup_Show(msgtext
)