vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 local tablet = AceLibrary("Tablet-2.0")
2 local abacus = AceLibrary("Abacus-2.0")
3  
4 local L = AceLibrary("AceLocale-2.2"):new("FuBar_ToFu")
5 ToFu = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceHook-2.0", "AceConsole-2.0", "AceDB-2.0", "FuBarPlugin-2.0")
6  
7 ToFu:RegisterDB("ToFuDB")
8 ToFu:RegisterDefaults('account', {
9 paths = {
10 Alliance = {['*']={}},
11 Horde = {['*']={}},
12 },
13 })
14 ToFu:RegisterDefaults('profile', {
15 hook = {
16 oCD = false,
17 oCB = false,
18 BigWigs = false,
19 Chronometer = false,
20 },
21 })
22 local optionsTable = {
23 handler = ToFu,
24 type = 'group',
25 args = {
26 hook = {
27 type = 'group', name = L['Hooks'],
28 desc = L['Other addons to hook into'],
29 args = {
30 oCD = {
31 type = 'toggle', name = 'oCD',
32 desc = 'otravi_CoolDown',
33 get = function() return ToFu.db.profile.hook.oCD end,
34 set = function(t) ToFu.db.profile.hook.oCD = t end,
35 disabled = function()
36 if oCD then return false
37 else return true end
38 end,
39 },
40 oCB = {
41 type = 'toggle', name = 'oCB',
42 desc = 'otravi_CastBar',
43 get = function() return ToFu.db.profile.hook.oCB end,
44 set = function(t) ToFu.db.profile.hook.oCB = t end,
45 disabled = function()
46 if oCB then return false
47 else return true end
48 end,
49 },
50 BigWigs = {
51 type = 'toggle', name = 'BigWigs',
52 desc = 'BigWigs_CustomBar',
53 get = function() return ToFu.db.profile.hook.BigWigs end,
54 set = function(t) ToFu.db.profile.hook.BigWigs = t end,
55 disabled = function()
56 if BigWigs and BigWigsCustomBar then return false
57 else return true end
58 end,
59 },
60 Chronometer = {
61 type = 'toggle', name = 'Chronometer',
62 desc = 'Chronometer',
63 get = function() return ToFu.db.profile.hook.Chronometer end,
64 set = function(t) ToFu.db.profile.hook.Chronometer = t end,
65 disabled = function()
66 if Chronometer then return false
67 else return true end
68 end,
69 },
70 },
71 },
72 data = {
73 type = 'group', name = L['Data'],
74 desc = L["Various options to do with saved flight data"],
75 args = {
76 clear = {
77 type = 'execute', name = L['Clear Data'],
78 desc = L["Delete *ALL* saved flight path data for your faction."],
79 func = "ClearData",
80 },
81 default = {
82 type = 'execute', name = L['Default Data'],
83 desc = L["Load the default flight-time dataset."],
84 func = function() ToFu:LoadDefaults() end, disabled = function() return type(ToFu.LoadDefaults) ~= 'function' end,
85 },
86 },
87 },
88 },
89 }
90  
91 ToFu:RegisterChatCommand({"/tofu",}, optionsTable)
92 ToFu.OnMenuRequest = optionsTable
93  
94 ToFu.version = "2.0." .. string.sub("$Revision: 15647 $", 12, -3)
95 ToFu.date = string.sub("$Date: 2006-10-31 20:34:49 -0500 (Tue, 31 Oct 2006) $", 8, 17)
96 ToFu.hasIcon = "Interface\\TaxiFrame\\UI-Taxi-Icon-Green"
97 ToFu.hideWithoutStandby = true
98  
99 function ToFu:OnInitialize()
100 self.start = nil
101 self.destination = nil
102 self.inFlight = false
103 self.timeFlown = 0
104 self.avgTime = nil
105 self.last, self.nodes, self.steps = {}, {}, {}
106  
107 --Stolen from AceDB
108 local _,race = UnitRace("player")
109 if race == "Orc" or race == "Scourge" or race == "Troll" or race == "Tauren" then
110 self.faction = 'Horde'
111 else
112 self.faction = 'Alliance'
113 end
114  
115 if not self.db.account.version then
116 self:ScheduleEvent(function()
117 --Check to see whether we need to shrink the database.
118 for faction, data in self.db.account.paths do
119 self:Print('Upgrading', faction, 'flight data')
120 --Convert the old data to the new format, and clear out the old DB in the process.
121 if type(data) ~= 'table' then data = nil
122 else
123 local newdata = {}
124 for start,dests in pairs(data) do
125 local newstart = self:LessName(start)
126 newdata[newstart] = {}
127 if type(dests) == 'table' then
128 for dest, info in pairs(dests) do
129 newdata[newstart][self:LessName(dest)] = info
130 data[start][dest] = nil
131 end
132 end
133 data[start] = nil
134 end
135 --Now apply the new data to the DB.
136 --(Can't merge this with the previous step, as it would be editing the table while looping over it.)
137 for start, dests in pairs(newdata) do
138 for dest, info in pairs(dests) do
139 if not self.db.account.paths[start] then self.db.account.paths[start] = {} end
140 self.db.account.paths[start][dest] = info
141 end
142 end
143 end
144 end
145  
146 self.db.account.version = 1
147 end, 1)
148 end
149 end
150  
151 function ToFu:OnEnable()
152 self:RegisterEvent("TAXIMAP_OPENED")
153 self:Hook("TakeTaxiNode")
154 self:Hook("TaxiNodeOnButtonEnter")
155 end
156  
157  
158 function ToFu:OnTextUpdate()
159 if self.inFlight then
160 if self.timeAvg ~= 0 then
161 --Time remaining, if we've taken this path before.
162 self:SetText(abacus:FormatDurationCondensed(self.timeAvg - self.timeFlown, true))
163 else
164 --Time flown so far.
165 self:SetText(abacus:FormatDurationCondensed(self.timeFlown, true))
166 end
167 else
168 self:SetText('')
169 end
170 end
171  
172 function ToFu:OnTooltipUpdate()
173 local cat = tablet:AddCategory(
174 'columns', 2,
175 'text', L["Current Flight"],
176 'child_textR', 1, 'child_textG', 0.82, 'child_textB', 0,
177 'child_text2R', 1, 'child_text2G', 1, 'child_text2B', 1
178 )
179 if self.inFlight then
180 cat:AddLine('text', L["From"], 'text2', self.start)
181 cat:AddLine('text', L["To"], 'text2', self.destination)
182 cat:AddLine('text', L["Time Taken"], 'text2', abacus:FormatDurationCondensed(self.timeFlown, true))
183 cat:AddLine('text', L["Average Time"], 'text2', abacus:FormatDurationCondensed(self.timeAvg, true))
184 cat:AddLine('text', L["Cost"], 'text2', abacus:FormatMoneyCondensed(self.cost, true))
185 else
186 cat:AddLine('text', L["Not in flight"])
187 end
188  
189 cat = tablet:AddCategory(
190 'columns', 2,
191 'text', L["Previous Flight"],
192 'child_textR', 1, 'child_textG', 0.82, 'child_textB', 0,
193 'child_text2R', 1, 'child_text2G', 1, 'child_text2B', 1
194 )
195 if self.last.start ~= nil then
196 cat:AddLine('text', L["From"], 'text2', self.last.start)
197 cat:AddLine('text', L["To"], 'text2', self.last.destination)
198 cat:AddLine('text', L["Time Taken"], 'text2', abacus:FormatDurationCondensed(self.last.time, true))
199 cat:AddLine('text', L["Cost"], 'text2', abacus:FormatMoneyCondensed(self.last.cost, true))
200 else
201 cat:AddLine('text', L["No previous flight"])
202 end
203  
204 if self.inFlight then
205 tablet:SetHint(L["Click to copy the time remaining in flight to the chatbox."])
206 end
207 end
208  
209 function ToFu:OnClick()
210 -- Paste time remaining to chatbox.
211 if ChatFrameEditBox:IsVisible() and self.inFlight then
212 local text = ""
213 local _, time = self:GetFlightData(self.start, self.destination)
214  
215 if time ~= 0 then
216 --Time remaining, if we've taken this path before.
217 text = abacus:FormatDurationFull(time - self.timeFlown, false)
218 else
219 --Time flown so far.
220 text = string.format("??? (%s %s)", abacus:FormatDurationFull(self.timeFlown, false), L["So Far"])
221 end
222  
223 ChatFrameEditBox:Insert(text)
224 end
225 end
226  
227  
228 function ToFu:OnUpdate(timeSinceLast)
229 self.timeFlown = self.timeFlown + timeSinceLast
230 if (UnitOnTaxi("player") ~= 1) and (self.timeFlown > 5) then
231 -- Cheap test to make sure that we don't do all this right at the beginning of a flight
232 self:CancelScheduledEvent(self.name)
233 self.inFlight = false
234  
235 local cost, time, taken = self:GetFlightData(self.start, self.destination)
236  
237 --Average time this route has taken (there's a chance we'll be getting inaccuracies, etc.):
238 if time ~= 0 then
239 time = (time + self.timeFlown) / 2
240  
241 if self.db.profile.hook.oCB and oCB then
242 oCB:SpellStop(true)
243 end
244 else
245 time = self.timeFlown
246 end
247  
248 self:SaveFlightData(self.start, self.destination, cost, time, taken + 1)
249  
250 self.last.start = self.start
251 self.last.destination = self.destination
252 self.last.time = self.timeFlown
253 self.last.cost = cost
254  
255 self.start = nil
256 self.destination = nil
257 self.timeFlown = nil
258 end
259 self:UpdateDisplay()
260 end
261  
262  
263 function ToFu:TAXIMAP_OPENED()
264 local numNodes = NumTaxiNodes()
265 -- Have to scan all the slots first to get the "CURRENT" slot.
266 for i=1, numNodes do
267 if TaxiNodeGetType(i) == "CURRENT" then
268 self.start = TaxiNodeName(i)
269 else
270 local x,y = TaxiNodePosition(i)
271 self.nodes[x..':'..y] = i
272 end
273 end
274 end
275  
276 function ToFu:TakeTaxiNode(slot)
277 if TaxiNodeGetType(slot) == "REACHABLE" then
278 self.destination = TaxiNodeName(slot)
279 self.timeFlown = 0
280 self.inFlight = true
281  
282 self.cost, self.timeAvg = self:GetFlightData(self.start, self.destination)
283  
284 if self.timeAvg ~= 0 then
285 if self.db.profile.hook.oCD and oCD then
286 --oCD:StartBar(id, time, text, icon)
287 oCD:StartBar('ToFu', self.timeAvg, self:LessName(self.destination), "Interface\\TaxiFrame\\UI-Taxi-Icon-Green")
288 end
289 if self.db.profile.hook.oCB and oCB then
290 --oCB:SpellStart(text, time, inSeconds, dontRegister)
291 oCB:SpellStart(self:LessName(self.destination), self.timeAvg, true, true)
292 end
293 if self.db.profile.hook.BigWigs and BigWigs and BigWigsCustomBar then
294 --BWCB(seconds, message)
295 BWLCB(self.timeAvg, "Flying to "..self:LessName(self.destination))
296 end
297 if self.db.profile.hook.Chronometer and Chronometer then
298 -- Chronometer:AddTimer(kind, name, duration, targeted, isgain, selforselect, extra)
299 if not Chronometer.timers[Chronometer.SPELL]['ToFu'] then Chronometer:AddTimer(Chronometer.SPELL, 'ToFu', self.timeAvg, 0, 0, 0) end
300 Chronometer:StartTimer(Chronometer.timers[Chronometer.SPELL]['ToFu'], self:LessName(self.destination))
301 end
302 end
303  
304 for key in pairs(self.nodes) do self.nodes[key] = nil end
305  
306 self:ScheduleRepeatingEvent(self.name, self.OnUpdate, 1, self, 1)
307 end
308 self.hooks["TakeTaxiNode"].orig(slot)
309 end
310  
311 function ToFu:TaxiNodeOnButtonEnter(button)
312 self.hooks["TaxiNodeOnButtonEnter"].orig(button)
313  
314 local index = button:GetID()
315 if TaxiNodeGetType(index) == "REACHABLE" then
316 local destination, cost = TaxiNodeName(index), TaxiNodeCost(index)
317 local oldcost, time, taken = self:GetFlightData(self.start, destination)
318 if oldcost ~= cost then self:SaveFlightData(self.start, destination, cost, time, taken) end
319  
320 local estimate = ''
321 if time == 0 then
322 --Try to estimate. This is mainly stolen from Blizzard's TaxiFrame.lua, which uses a much more in-depth version of this to draw the lines.
323 local _,reversetime = self:GetFlightData(destination, self.start)
324 if reversetime > 0 then
325 time = reversetime
326 estimate = L['reversed']
327 else
328 local numRoutes = GetNumRoutes(index)
329 if numRoutes > 1 then
330 TaxiNodeSetCurrent(index) --This is magic -- it renumbers the 'hops' between index and current so the for loop below works.
331 self.steps[1] = self.start
332  
333 local length = 0
334 for i=1, numRoutes do
335 local l, dx, dy = self:LineLength(index, i)
336 length = length + l
337  
338 self.steps[i+1] = TaxiNodeName(self.nodes[dx..':'..dy])
339 end
340  
341 local skipped = 0
342 local node = 1
343 while node <= numRoutes do
344 --self.steps[node] is the 'current' node.
345 --Step backwards through self.steps to find the longest interval that gives us a time.
346 local nnode = numRoutes+1
347 while nnode > node do
348 local _,t = self:GetFlightData(self.steps[node], self.steps[nnode])
349 if t==0 then _,t = self:GetFlightData(self.steps[nnode], self.steps[node]) end
350 nnode = nnode - 1
351 if t > 0 then
352 -- We know this! Add it to the time and skip the rest of the loops.
353 time = time + t
354 break
355 elseif nnode == node then
356 -- We have no idea. Mark down that we skipped this.
357 skipped = skipped + self:LineLength(index, node-1) -- Is 'node-1' right here?
358 break
359 end
360 end
361 node = nnode + 1
362 end
363 if time > 0 then
364 if skipped > 0 then time = time + ((time/(length-skipped)) * skipped) end
365 estimate = ' '..L['estimated']
366 end
367  
368 for key in pairs(self.steps) do self.steps[key] = nil end
369 end
370 end
371 end
372  
373 GameTooltip:AddLine(L["Takes"]..": "..abacus:FormatDurationCondensed(time)..estimate, 1, 1, 1)
374 GameTooltip:AddLine(string.format(L["Flown %s times"], taken), 1, 1, 1)
375 GameTooltip:SetHeight(GameTooltip:GetHeight() + 28)
376 end
377 end
378  
379 function ToFu:LessName(s)
380 --For "Thelsamar, Loch Modan" return "Thelsamar".
381 if not s then return '' end
382 if ( GetLocale() ~= "koKR" ) then
383 local c = string.find(s, ', ')
384 if c then s = string.sub(s, 1, c-1) end
385 else
386 local c = string.find(s, ' %(')
387 if c then _,_,s = string.find(s, "(.-) %(") end
388 end
389 return s
390 end
391  
392 -- Data in format: ":1000:120:3:"
393 -- Means: "cost 1000 copper, taking 120 seconds, taken 3 times."
394  
395 function ToFu:GetFlightData(start, destination, faction)
396 -- cost, time, taken = ToFu:GetFlightData(start, destination, faction)
397 -- Fetches the saved information about a flight path, from [start] to [destination].
398 -- If any arguments are left as nil, the current value of self.<<argument>> will be used.
399 local s = self.db.account.paths[faction or self.faction][self:LessName(start or self.start)][self:LessName(destination or self.destination)]
400 if type(s) ~= 'string' then return 0,0,0 end
401 local _, _, cost, time, taken = string.find(s, ":(%d+):(%d+):(%d+):")
402 return (tonumber(cost) or 0), (tonumber(time) or 0), (tonumber(taken) or 0), self:LessName(start or self.start), self:LessName(destination or self.destination)
403 end
404  
405 function ToFu:SaveFlightData(start, destination, cost, time, taken, faction)
406 self.db.account.paths[faction or self.faction][self:LessName(start)][self:LessName(destination)] = ':'..(cost or 0)..':'..math.floor((time and tonumber(time) or 0))..':'..(taken or 0)..':'
407 return true
408 end
409  
410 function ToFu:ClearData()
411 self.db.account.paths[self.faction] = {}
412 end
413  
414 function ToFu:LineLength(index, i)
415 --Start node:
416 local sx = TaxiGetSrcX(index, i)
417 local sy = TaxiGetSrcY(index, i)
418 --End node:
419 local ex = TaxiGetDestX(index, i)
420 local ey = TaxiGetDestY(index, i)
421 -- Determine dimensions
422 local dx,dy = ex - sx, ey - sy;
423 -- Normalize direction if necessary
424 if (dx < 0) then
425 dx,dy = -dx,-dy;
426 end
427 -- Return length and endpoint coords.
428 return sqrt((dx * dx) + (dy * dy)), ex, ey
429 end