Added rightclick to map button, desaturated it when QuestHelper is hidden, and change...
[QuestHelper.git] / utility.lua
blobff080a9006cbcbd210c9ca39026e54316d2155a3
1 local default_colour_theme =
2 {message_prefix={0.4, 0.78, 1},
3 message={1, 0.6, 0.2},
4 tooltip={1, 0.8, 0.5},
5 message_highlight={0.73, 1, 0.84},
6 menu_text={1, 1, 1},
7 menu_text_highlight={0, 0, 0},
8 menu={0, 0, 0},
9 menu_highlight={0.3, 0.5, 0.7},
10 menu_title_text={1, 1, 1},
11 menu_title_text_highlight={1, 1, 1},
12 menu_title={0, 0.2, 0.6},
13 menu_title_highlight={0.1, 0.4, 0.8}}
15 local xmas_colour_theme =
16 {message_prefix={0.0, 0.7, 0.0},
17 message={0.2, 1, 0.2},
18 tooltip={0.4, 1, 0.4},
19 message_highlight={1, 0.3, 0.1},
20 menu_text={1, 1, 1},
21 menu_text_highlight={0, 0, 0},
22 menu={0.2, 0, 0},
23 menu_highlight={1, 0.3, 0.3},
24 menu_title_text={0.8, 1, 0.8},
25 menu_title_text_highlight={1, 1, 1},
26 menu_title={0.2, 0.6, 0.2},
27 menu_title_highlight={0.4, 0.7, 0.4}}
29 function QuestHelper:GetColourTheme()
30 if date("%b%d") == "Dec25" then
31 return xmas_colour_theme
32 end
34 return default_colour_theme
35 end
37 QuestHelper.nop = function () end -- Who wouldn't want a function that does nothing?
39 function QuestHelper:HashString(text)
40 -- Computes an Adler-32 checksum.
41 local a, b = 1, 0
42 for i=1,string.len(text) do
43 a = (a+string.byte(text,i))%65521
44 b = (b+a)%65521
45 end
46 return b*65536+a
47 end
49 function QuestHelper:CreateUID(length)
50 local result = ""
51 local characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
52 math.randomseed(math.random(0, 2147483647)+GetTime()*100000)
53 local base = GetUnitName("player")..":"..GetRealmName()..":"..math.random(0, 2147483647)..":"..GetTime()..":"..time()
55 for c = 1,(length or 32) do
56 local pos = 1+math.floor(self:HashString(result..base..math.random(0, 2147483647))%string.len(characters))
57 result = result .. string.sub(characters, pos, pos)
58 end
60 return result
61 end
63 function QuestHelper:ZoneSanity()
64 local sane = true
66 for c=1, select("#", GetMapContinents()) do
67 for z=0, select("#", GetMapZones(c)) do
68 local name
70 if z == 0 then
71 name = select(c, GetMapContinents())
72 else
73 name = select(z, GetMapZones(c))
74 end
76 assert(name)
78 if QuestHelper_Zones[c][z] ~= name then
79 sane = false
80 QuestHelper:TextOut("'"..name.."' has the wrong ID.")
81 end
83 local pair = QuestHelper_ZoneLookup[name]
85 if not pair or c ~= pair[1] or z ~= pair[2] then
86 sane = false
87 QuestHelper:TextOut("ZoneLookup['"..name.."'] maps to wrong pair.")
88 end
90 local index = QuestHelper_IndexLookup[name]
91 if QuestHelper_ZoneLookup[index] ~= pair then
92 sane = false
93 QuestHelper:TextOut("ZoneLookup['"..name.."'] isn't equal to ZoneLookup["..index.."]")
94 end
96 if not index or QuestHelper_NameLookup[index] ~= name then
97 sane = false
98 QuestHelper:TextOut("NameLookup["..(index or "???").."'] doesn't equal '"..name.."'")
99 end
103 return sane
106 function QuestHelper:TextOut(text)
107 local theme = self:GetColourTheme()
108 DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff%2x%2x%2xQuestHelper: |r%s", theme.message_prefix[1]*255,
109 theme.message_prefix[2]*255,
110 theme.message_prefix[3]*255, text),
111 theme.message[1],
112 theme.message[2],
113 theme.message[3])
116 function QuestHelper:Error(what)
117 DEFAULT_CHAT_FRAME:AddMessage("QuestHelper Error: "..(what or "Unknown").."\n"..debugstack(2), 1,.5,0)
118 error("Abort!")
121 function QuestHelper:HighlightText(text)
122 local theme = self:GetColourTheme()
123 return string.format("|cff%2x%2x%2x%s|r", theme.message_highlight[1]*255,
124 theme.message_highlight[2]*255,
125 theme.message_highlight[3]*255, text)
128 function QuestHelper:GetUnitID(unit)
129 local id = UnitGUID(unit)
131 if id then
132 return (string.sub(id, 5, 5) == "3") and tonumber(string.sub(id, 6, 12), 16) or nil
135 return nil
138 function QuestHelper:GetQuestID(index)
139 return tonumber(select(3, string.find(GetQuestLink(index), "|Hquest:(%d+):")))
142 -- For future reference:
143 -- Hearthstone = 6948
144 -- Rune of Teleportation = 17031
145 -- Rune of Portals = 17032
147 function QuestHelper:CountItem(item_id)
148 local count = 0
150 for bag = 0,NUM_BAG_SLOTS do
151 for slot = 1,GetContainerNumSlots(bag) do
152 local link = GetContainerItemLink(bag, slot)
153 if link and string.find(link, string.format("|Hitem:%d:", item_id)) then
154 count = count + (select(2, GetContainerItemInfo(bag, slot)) or 0)
159 return count
162 function QuestHelper:ItemCooldown(item_id)
163 local now = GetTime()
164 local cooldown = nil
166 for bag = 0,NUM_BAG_SLOTS do
167 for slot = 1,GetContainerNumSlots(bag) do
168 local link = GetContainerItemLink(bag, slot)
169 if link and string.find(link, string.format("|Hitem:%d:", item_id)) then
170 local s, d, e = GetContainerItemCooldown(bag, slot)
171 if e then
172 if cooldown then
173 cooldown = math.min(cooldown, math.max(0, d-now+s))
174 else
175 cooldown = math.max(0, d-now+s)
177 else
178 return 0
184 return cooldown
187 function QuestHelper:TimeString(seconds)
188 local seconds = math.ceil(seconds)
189 local h, m, s = math.floor(seconds/(60*60)), math.floor(seconds/60)%60, seconds%60
190 if h > 0 then
191 return string.format("|cffffffff%d|r:|cffffffff%02d|r:|cffffffff%02d|r", h, m, s)
192 else
193 return string.format("|cffffffff%d|r:|cffffffff%02d|r", m, s)
197 function QuestHelper:ProgressString(str, pct)
198 if pct > 1 then
199 return string.format("|cff00ff00%s|r", str)
200 elseif pct < 0 then
201 return string.format("|cffff0000%s|r", str)
202 elseif pct > 0.5 then
203 return string.format("|cff%2xff00%s|r", 510-pct*510, str)
204 else
205 return string.format("|cffff%2x00%s|r", pct*510, str)
209 function QuestHelper:PercentString(pct)
210 if pct > 1 then
211 return string.format("|cff00ff00%.1f%%|r", pct*100)
212 elseif pct < 0 then
213 return string.format("|cffff0000%.1f%%|r", pct*100)
214 elseif pct > 0.5 then
215 return string.format("|cff%2xff00%.1f%%|r", 510-pct*510, pct*100)
216 else
217 return string.format("|cffff%2x00%.1f%%|r", pct*510, pct*100)
221 function QuestHelper:PlayerPosition()
222 return self.i, self.x, self.y
225 function QuestHelper:UnitPosition(unit)
226 local c, z, x, y = self.Astrolabe:GetUnitPosition(unit,true)
227 if c then
228 if z == 0 then
229 SetMapToCurrentZone()
230 z = GetCurrentMapZone()
231 if z ~= 0 then
232 x, y = self.Astrolabe:TranslateWorldMapPosition(c, 0, x, y, c, z)
235 return QuestHelper_IndexLookup[c][z], x, y
236 else
237 return self:PlayerPosition()
241 function QuestHelper:LocationString(i, x, y)
242 return ("[|cffffffff%s|r:|cffffffff%d,%.3f,%.3f|r]"):format(QuestHelper_NameLookup[i] or "nil", i, x, y)
245 function QuestHelper:Distance(i1, x1, y1, i2, x2, y2)
246 local p1, p2 = QuestHelper_ZoneLookup[i1], QuestHelper_ZoneLookup[i2]
247 return self.Astrolabe:ComputeDistance(p1[1], p1[2], x1, y1, p2[1], p2[2], x2, y2) or 10000
250 function QuestHelper:AppendPosition(list, index, x, y, w, min_dist)
251 if (x == 0 and y == 0) or x <= -0.1 or y <= -0.1 or x >= 1.1 or y >= 1.1 then
252 return list -- This isn't a real position.
255 local closest, distance = nil, 0
256 w = w or 1
257 min_dist = min_dist or 200
259 for i, p in ipairs(list) do
260 if index == p[1] then
261 local d = self:Distance(index, x, y, p[1], p[2], p[3])
262 if not closest or d < distance then
263 closest, distance = i, d
268 if closest and distance < min_dist then
269 local p = list[closest]
270 p[2] = (p[2]*p[4]+x*w)/(p[4]+w)
271 p[3] = (p[3]*p[4]+y*w)/(p[4]+w)
272 p[4] = p[4]+w
273 else
274 table.insert(list, {index, x, y, w})
277 return list
280 function QuestHelper:PositionListDistance(list, index, x, y)
281 local closest, distance = nil, 0
282 for i, p in ipairs(list) do
283 local d = self:Distance(index, x, y, p[1], p[2], p[3])
284 if not closest or d < distance then
285 closest, distance = p, d
288 if closest then
289 return distance, closest[1], closest[2], closest[3]
293 function QuestHelper:PositionListDistance2(list, i1, x1, y1, i2, x2, y2)
294 local closest, bd1, bd2, bdt = nil, 0, 0, 0
295 for i, p in ipairs(list) do
296 local d1 = self:Distance(i1, x1, y1, p[1], p[2], p[3])
297 local d2 = self:Distance(i2, x2, y2, p[1], p[2], p[3])
298 local t = d1+d2
299 if not closest or t < bdt then
300 closest, bd1, bd2, bdt = p, d1, d2, t
303 if closest then
304 return d1, d2, closest[1], closest[2], closest[3]
308 function QuestHelper:MergePositions(list1, list2)
309 for i, p in ipairs(list2) do
310 self:AppendPosition(list1, unpack(p))
314 function QuestHelper:MergeDrops(list1, list2)
315 for element, count in pairs(list2) do
316 list1[element] = (list1[element] or 0) + count