1 QuestHelper_File
["tracker.lua"] = "Development Version"
3 local tracker
= CreateFrame("Frame", "QuestHelperQuestWatchFrame", UIParent
)
4 local minbutton
= CreateFrame("Button", "QuestHelperQuestWatchFrameMinimizeButton", UIParent
)
6 QuestHelper
.tracker
= tracker
10 tracker
:SetHeight(100)
11 tracker
.dw
, tracker
.dh
= 200, 100
15 minbutton
:SetFrameStrata("DIALOG")
17 minbutton
:SetPoint("CENTER", QuestWatchFrame
) -- We default to a different location to make it more likely to display the right item.
18 minbutton
:SetMovable(true)
19 minbutton
:SetUserPlaced(true)
20 minbutton
:SetWidth(10)
21 minbutton
:SetHeight(5)
22 local minbutton_tex
= minbutton
:CreateTexture()
23 minbutton_tex
:SetAllPoints()
24 minbutton_tex
:SetTexture(.8, .8, .8)
26 tracker
:SetPoint("CENTER", minbutton
)
28 function minbutton
:moved()
29 local x
, y
= self
:GetCenter()
30 local w
, h
= UIParent
:GetWidth(), UIParent
:GetHeight()
31 local anchor
= (y
< h
*.45 and "BOTTOM" or y
> h
*.55 and "TOP" or "")..(x
< w
*.45 and "LEFT" or x
> w
*.55 and "RIGHT" or "")
33 tracker
:ClearAllPoints()
34 tracker
:SetPoint("CENTER", self
)
37 tracker
:SetPoint(anchor
, self
)
41 function QuestHelper
:ResetTrackerPosition(cmd
)
42 minbutton
:ClearAllPoints()
43 if string.find(cmd
, "center") then
44 minbutton
:SetPoint("CENTER", nil, "CENTER", 100, 100)
46 minbutton
:SetPoint("RIGHT", nil, "RIGHT", -20, 230)
49 self
:TextOut("Quest tracker postion reset.")
52 minbutton
:SetScript("OnEvent", minbutton
.moved
)
53 minbutton
:RegisterEvent("DISPLAY_SIZE_CHANGED")
54 minbutton
:RegisterEvent("PLAYER_ENTERING_WORLD")
56 minbutton
:SetScript("OnClick", function ()
57 QuestHelper_Pref
.track_minimized
= not QuestHelper_Pref
.track_minimized
58 if QuestHelper_Pref
.track_minimized
then
65 minbutton
:RegisterForDrag("LeftButton")
67 minbutton
:SetScript("OnDragStart", function(self
)
68 if self
:IsVisible() then
70 self
:SetScript("OnUpdate", self
.moved
)
74 minbutton
:SetScript("OnDragStop", function(self
)
75 self
:SetScript("OnUpdate", nil)
76 self
:StopMovingOrSizing()
80 minbutton
:SetScript("OnEnter", function (self
)
84 minbutton
:SetScript("OnLeave", function (self
)
85 self
:SetAlpha(QuestHelper_Pref
.track_minimized
and .3 or .5)
88 local unused_items
= {}
91 local function itemupdate(item
, delta
)
94 local a
= item
:GetAlpha()
104 local t
= item
.t
+ delta
109 local sp
= math
.sqrt(t
-t
*t
)
110 item
.x
, item
.y
= item
.sx
*it
+item
.dx
*t
+(item
.sy
-item
.dy
)*sp
, item
.sy
*it
+item
.dy
*t
+(item
.dx
-item
.sx
)*sp
114 item
.x
, item
.y
= item
.dx
, item
.dy
117 item
:ClearAllPoints()
118 item
:SetPoint("TOPLEFT", tracker
, "TOPLEFT", item
.x
, item
.y
)
121 item
:SetScript("OnUpdate", nil)
125 local function itemfadeout(item
, delta
)
126 local a
= item
:GetAlpha()
134 item
:SetScript("OnUpdate", nil)
138 local t
= item
.t
+ delta
143 local sp
= math
.sqrt(t
-t
*t
)
144 item
.x
, item
.y
= item
.sx
*it
+item
.dx
*t
+(item
.sy
-item
.dy
)*sp
, item
.sy
*it
+item
.dy
*t
+(item
.dx
-item
.sx
)*sp
147 item
.x
, item
.y
= item
.dx
, item
.dy
150 item
:ClearAllPoints()
151 item
:SetPoint("TOPLEFT", tracker
, "TOPLEFT", item
.x
, item
.y
)
154 function QH_ToggleQuestLog() -- This seems to be gone in 3.0, so I'm adding it here.
155 if (QuestLogFrame
:IsShown()) then
156 HideUIPanel(QuestLogFrame
);
158 ShowUIPanel(QuestLogFrame
);
163 local function itemclick(item
, button
)
164 if button
== "RightButton" then
165 local quest
= item
.quest
168 local title
= GetQuestLogTitle(index
)
169 if not title
then break end
171 if title
== quest
then
173 -- UberQuest needs a little extra effort to work properly.
175 if UberQuest_List
:IsShown() and GetQuestLogSelection() == index
then
178 QuestLog_SetSelection(index
)
180 -- By hiding the list, the replaced ToggleQuestLog function should try to reshow it
181 -- and in the process update the frames to reflect the selected quest.
182 UberQuest_List
:Hide()
183 UberQuest_Details
:Show()
187 -- This code seems to work properly with the builtin questlog, as well as bEQL and DoubleWide.
189 if QuestLogFrame
:IsShown() and GetQuestLogSelection() == index
then
190 -- If the selected quest is already being shown, hide it.
193 -- Otherwise, select it and show it.
194 QuestLog_SetSelection(index
)
196 if not QuestLogFrame
:IsShown() then
210 local function addItem(name
, quest
, obj
, y
, qname
)
211 local x
= qname
and 4 or 20
212 local item
= used_items
[quest
] and used_items
[quest
][obj
]
214 item
= next(unused_items
)
216 unused_items
[item
] = nil
218 item
= CreateFrame("Frame", nil, tracker
)
219 item
.text
= item
:CreateFontString()
220 item
.text
:SetShadowColor(0, 0, 0, .8)
221 item
.text
:SetShadowOffset(1, -1)
222 item
.text
:SetPoint("TOPLEFT", item
)
226 item
.text
:SetFont(QuestHelper
.font
.serif
, 12)
227 item
.text
:SetTextColor(.82, .65, 0)
229 item
.text
:SetFont(QuestHelper
.font
.sans
, 12)
230 item
.text
:SetTextColor(.82, .82, .82)
233 if not used_items
[quest
] then used_items
[quest
] = {} end
235 used_items
[quest
][obj
] = item
236 item
.sx
, item
.sy
, item
.x
, item
.y
, item
.dx
, item
.dy
, item
.t
= x
+30, y
, x
, y
, x
, y
, 0
237 item
:SetScript("OnUpdate", itemupdate
)
245 item
.text
:SetText(name
)
246 local w
, h
= item
.text
:GetWidth(), item
.text
:GetHeight()
251 item
:SetScript("OnMouseDown", itemclick
)
252 item
:EnableMouse(true)
255 if item
.dx
~= x
or item
.dy
~= y
then
256 item
.sx
, item
.sy
, item
.dx
, item
.dy
= item
.x
, item
.y
, x
, y
258 item
:SetScript("OnUpdate", itemupdate
)
264 local function ccode(r1
, g1
, b1
, r2
, g2
, b2
, p
)
266 p
, ip
= p
*255, 255-p
*255
267 return string.format("|cff%02x%02x%02x", r1
*ip
+r2
*p
, g1
*ip
+g2
*p
, b1
*ip
+b2
*p
)
270 local function qname(title
, level
)
271 if QuestHelper_Pref
.track_level
then
272 title
= string.format("[%d] %s", level
, title
)
275 if QuestHelper_Pref
.track_qcolour
then
276 local player_level
= QuestHelper
.player_level
277 local delta
= level
- player_level
282 colour
= "|cffff0000"
283 elseif delta
>= 0 then
284 colour
= ccode(1, 1, 0, 1, 0, 0, delta
/5)
288 if player_level
>= 60 then grey
= player_level
- 9
289 elseif player_level
>= 40 then grey
= player_level
- math
.floor(player_level
/5) - 1
290 elseif player_level
>= 6 then grey
= player_level
- math
.floor(player_level
/10) - 5
294 colour
= ccode(0, 1, 0, 1, 1, 0, (grey
-level
)/(grey
-player_level
))
296 colour
= ccode(.4, .4, .4, .2, .8, .2, (1-level
)/(1-grey
))
300 title
= string.format("%s%s", colour
, title
)
306 local function oname(text
, pct
)
307 if QuestHelper_Pref
.track_ocolour
then
308 text
= string.format("%s%s", pct
< 0.5 and ccode(1, 0, 0, 1, 1, 0, pct
*2) or ccode(1, 1, 0, 0, 1, 0, pct
*2-1), text
)
314 local function removeUnusedItem(quest
, obj
, item
)
315 unused_items
[item
] = true
316 used_items
[quest
][obj
] = nil
317 if not next(used_items
[quest
]) then used_items
[quest
] = nil end
320 item
.sx
, item
.sy
= item
.x
, item
.y
321 item
.dx
, item
.dy
= item
.x
+30, item
.y
322 item
:SetScript("OnMouseDown", nil)
323 item
:EnableMouse(false)
324 item
:SetScript("OnUpdate", itemfadeout
)
327 local resizing
= false
328 local check_delay
= 4
331 local obj_index_lookup
= {}
332 local quest_lookup
= {}
333 local was_inside
= false
335 local function watched_filter(obj
)
336 return obj
:IsWatched()
339 local function objlist_sort(a
, b
)
340 return (obj_index_lookup
[a
] or 0) < (obj_index_lookup
[b
] or 0)
343 function tracker
:reset()
344 for quest
, objs
in pairs(used_items
) do
345 for obj
, item
in pairs(objs
) do
346 removeUnusedItem(quest
, obj
, item
)
352 local function addobj(objective
, seen
, obj_index_lookup
, filter
, x
, y
, gap
)
356 if objective
.cat
== "quest" then
359 quest
= objective
.quest
362 if quest
and quest
.watched
and not seen
[quest
] and (not filter
or filter(quest
)) then
365 local level
, name
= string.match(quest
.obj
, "^(%d+)/%d*/(.*)$")
368 level
, name
= string.match(quest
.obj
, "^(%d+)/(.*)$")
370 level
, name
= 1, quest
.obj
374 level
= tonumber(level
) or 1
377 local w
, h
= addItem(qname(name
, level
), true, quest
, -(y
+gap
), name
)
382 for obj
in pairs(quest
.swap_after
or quest
.after
) do
384 table.insert(obj_list
, obj
)
388 table.sort(obj_list
, objlist_sort
)
390 for i
, obj
in ipairs(obj_list
) do
391 local pct
, text
= 0, obj
.obj
392 local seen_sum
, seen_max
= 0, 0
395 local seen_have
, seen_need
= QuestHelper
:CreateTable(), QuestHelper
:CreateTable()
397 for user
, progress
in pairs(obj
.progress
) do
398 seen_sum
= seen_sum
+ progress
[3]
399 seen_max
= seen_max
+ 1
400 seen_have
[progress
[1]]
= true
401 seen_need
[progress
[2]]
= true
405 pct
= seen_sum
/ seen_max
406 local list
= QuestHelper
:CreateTable()
408 for val
in pairs(seen_have
) do
409 table.insert(list
, val
)
414 local have
= table.concat(list
, ", ")
416 for i
= #list
,1,-1 do
420 for val
in pairs(seen_need
) do
421 table.insert(list
, val
)
424 if #list
~= 1 or list
[1] ~= 1 then
425 -- If there is only one thing needed, ignore the progress, it's redundant.
426 -- It's either shown or it isn't.
430 local need
= table.concat(list
, ", ")
432 text
= string.format((tonumber(have
) and tonumber(need
) and QUEST_ITEMS_NEEDED
) or QUEST_FACTION_NEEDED
,
436 QuestHelper
:ReleaseTable(list
)
439 QuestHelper
:ReleaseTable(seen_have
)
440 QuestHelper
:ReleaseTable(seen_need
)
443 if seen_sum
~= seen_max
then
445 w
, h
= addItem(oname(text
, pct
), quest
, obj
, -y
)
451 for i
= #obj_list
, 1, -1 do obj_list
[i
] = nil end
454 return x
, y
, gap
, count
457 function tracker
:update(delta
)
459 -- This is called without a value when the questlog is updated.
460 -- We'll make sure we update the display on the next update.
466 local t
= self
.t
+delta
469 self
:SetWidth(self
.dw
)
470 self
:SetHeight(self
.dh
)
475 self
:SetWidth(self
.sw
*it
+self
.dw
*t
)
476 self
:SetHeight(self
.sh
*it
+self
.dh
*t
)
480 -- Manually checking if the mouse is in the frame, because if I used on OnEnter, i'd have to enable mouse input,
481 -- and if I did that, it would prevent the player from using the mouse to change the view if they clicked inside
483 local x
, y
= GetCursorPosition()
484 local s
= 1/self
:GetEffectiveScale()
487 local inside
= x
>= self
:GetLeft() and y
>= self
:GetBottom() and x
< self
:GetRight() and y
< self
:GetTop()
488 if inside
~= was_inside
then
491 minbutton
:SetAlpha(.7)
492 elseif not QuestHelper_Pref
.track_minimized
then
493 minbutton
:SetAlpha(0)
497 check_delay
= check_delay
+ delta
498 if check_delay
> 5 then
501 local quests
= QuestHelper
.quest_log
505 local track_size
= QuestHelper_Pref
.track_size
507 for quest
, objs
in pairs(used_items
) do
508 for obj
, item
in pairs(objs
) do
513 for i
, objective
in pairs(QuestHelper
.route
) do
514 if objective
.watched
then
515 obj_index_lookup
[objective
] = i
519 for q
, data
in pairs(QuestHelper
.quest_log
) do
520 quest_lookup
[data
.index
] = q
523 -- Add Quests that are watched but not in the route.
525 local uq_settings
= UberQuest_Config
[UnitName("player")]
527 local list
= uq_settings
.selected
531 local name
= GetQuestLogTitle(i
)
532 if not name
then break end
533 quest_lookup
[name
] = quest_lookup
[i
]
536 for name
in pairs(list
) do
537 local q
= quest_lookup
[name
]
538 if q
and not obj_index_lookup
[q
] then
540 x
, y
, gap
, count
= addobj(q
, seen
, obj_index_lookup
, nil, x
, y
, gap
)
541 added
= added
+ count
547 for i
= 1,GetNumQuestWatches() do
548 local q
= quest_lookup
[GetQuestIndexForWatch(i
)]
549 if q
and not obj_index_lookup
[q
] then
551 x
, y
, gap
, count
= addobj(q
, seen
, obj_index_lookup
, nil, x
, y
, gap
)
552 added
= added
+ count
557 -- Add Quests that are watched and are in the route.
558 for i
, objective
in ipairs(QuestHelper
.route
) do
560 x
, y
, gap
, count
= addobj(objective
, seen
, obj_index_lookup
, watched_filter
, x
, y
, gap
)
561 added
= added
+ count
564 -- Add an extra large gap to seperate the watched objectives from the automatic objectives.
567 -- Add Quests that aren't watched and are in the route.
568 if added
<= track_size
then
569 for i
, objective
in ipairs(QuestHelper
.route
) do
571 x
, y
, gap
, count
= addobj(objective
, seen
, obj_index_lookup
, nil, x
, y
, gap
)
572 added
= added
+ count
574 if added
> track_size
then
580 for obj
in pairs(obj_index_lookup
) do
581 obj_index_lookup
[obj
] = nil
584 for key
in pairs(quest_lookup
) do
585 quest_lookup
[key
] = nil
588 for quest
, objs
in pairs(used_items
) do
589 for obj
, item
in pairs(objs
) do
590 if not item
.used
then
591 removeUnusedItem(quest
, obj
, item
)
596 for key
in pairs(seen
) do
602 if x
~= tracker
.dw
or y
~= tracker
.dy
then
604 tracker
.sw
, tracker
.sh
= tracker
:GetWidth(), tracker
:GetHeight()
605 tracker
.dw
, tracker
.dh
= x
, y
613 tracker
:SetScript("OnUpdate", tracker
.update
)
615 -- Some hooks to update the tracker when quests are added or removed.
616 local orig_AddQuestWatch
, orig_RemoveQuestWatch
= AddQuestWatch
, RemoveQuestWatch
618 function AddQuestWatch(...)
620 return orig_AddQuestWatch(...)
623 function RemoveQuestWatch(...)
625 return orig_RemoveQuestWatch(...)
628 -------------------------------------------------------------------------------------------------
629 -- This batch of stuff is to make sure the original tracker (and any modifications) stay hidden
631 local orig_TrackerOnShow
= QuestWatchFrame
:GetScript("OnShow")
632 local orig_TrackerBackdropOnShow
-- bEQL (and perhaps other mods) add a backdrop to the tracker
633 local TrackerBackdropFound
= false
635 local function TrackerBackdropOnShow(self
, ...)
636 if QuestHelper_Pref
.track
and not QuestHelper_Pref
.hide
then
637 TrackerBackdropFound
:Hide()
640 if orig_TrackerBackdropOnShow
then
641 return orig_TrackerBackdropOnShow(self
, ...)
645 function tracker
:HideDefaultTracker()
646 -- The easy part: hide the original tracker
647 QuestWatchFrame
:Hide()
649 -- The harder part: check if a known backdrop is present (but we don't already know about it).
650 -- If it is, make sure it's hidden, and hook its OnShow to make sure it stays that way.
651 -- Unfortunately, I can't figure out a good time to check for this once, so we'll just have
652 -- to keep checking. Hopefully, this won't happen too often.
653 if not TrackerBackdropFound
then
654 if QuestWatchFrameBackdrop
then
655 -- Found bEQL's QuestWatchFrameBackdrop...
656 TrackerBackdropFound
= QuestWatchFrameBackdrop
659 if TrackerBackdropFound
then
660 -- OK, we found something - so hide it, and make sure it doesn't rear its ugly head again
661 TrackerBackdropFound
:Hide()
663 orig_TrackerBackdropOnShow
= TrackerBackdropFound
:GetScript("OnShow")
664 TrackerBackdropFound
:SetScript("OnShow", TrackerBackdropOnShow
)
669 function tracker
:ShowDefaultTracker()
670 QuestWatchFrame
:Show()
672 -- Make sure the default tracker is up to date on what what's being watched and what isn't.
675 if TrackerBackdropFound
then
676 TrackerBackdropFound
:Show()
680 local function QuestWatchFrameOnShow(self
, ...)
681 if QuestHelper_Pref
.track
and not QuestHelper_Pref
.hide
then
682 tracker
:HideDefaultTracker()
685 if orig_TrackerOnShow
then
686 return orig_TrackerOnShow(self
, ...)
690 QuestWatchFrame
:SetScript("OnShow", QuestWatchFrameOnShow
)
692 function QuestHelper
:ShowTracker()
693 tracker
:HideDefaultTracker()
696 if QuestHelper_Pref
.track_minimized
then
697 minbutton
:SetAlpha(.3)
699 minbutton
:SetAlpha(0)
704 function QuestHelper
:HideTracker()
705 tracker
:ShowDefaultTracker()