vanilla-wow-addons – Rev 1
?pathlinks?
local tablet = AceLibrary("Tablet-2.0")
local compost = AceLibrary("Compost-2.0")
local deformat = AceLibrary("Deformat-2.0")
local babbleclass = AceLibrary("Babble-Class-2.0")
local crayon = AceLibrary("Crayon-2.0")
local tourist = AceLibrary("Tourist-2.0")
local L = AceLibrary("AceLocale-2.0"):new("QuestsFu")
QuestsFu = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceHook-2.0", "AceConsole-2.0", "AceDB-2.0", "FuBarPlugin-2.0")
QuestsFu:RegisterDB("QuestsFuDB")
QuestsFu:RegisterDefaults('profile', {
showLevelsGame = true,
showLevelsTablet = true,
showLevelsZone = true,
showDifficulty = true,
showImpossible = true,
showArea = true,
showCurrentAreaOnly = false,
showClassAnyway = true,
showCurrentAreaDescriptionOnly = false,
showDescription = true,
showCompletedObjectives = false,
showInItemTooltip = true,
colorObjectives = true,
wrapQuests = true,
showTextOpt = {
total = true,
current = true,
complete = false,
lastmessage = true,
},
})
QuestsFu:RegisterDefaults('char', {
hidden = {},
watchedQuests = {},
})
QuestsFu.version = "2.0." .. string.sub("$Revision: 10107 $", 12, -3)
QuestsFu.date = string.sub("$Date: 2006-09-04 13:31:04 -0700 (Mon, 04 Sep 2006) $", 8, 17)
QuestsFu.hasIcon = true
QuestsFu.clickableTooltip = true
QuestsFu.cannotHideText = true
local optionsTable = {
handler = QuestsFu,
type = 'group',
args = {
show = {
type = 'group',
name = L["OPT_show"],
desc = L["OPT_show_d"],
args = {
text = {
type = 'group',
name = L["OPT_text"],
desc = L["OPT_text_d"],
args = {
current = {
type = 'toggle',
name = L["OPT_current"],
desc = L["OPT_current_d"],
get = "IsShowingTextCurrent",
set = "ToggleShowingTextCurrent",
},
complete = {
type = 'toggle',
name = L["OPT_complete"],
desc = L["OPT_complete_d"],
get = "IsShowingTextComplete",
set = "ToggleShowingTextComplete",
},
total = {
type = 'toggle',
name = L["OPT_total"],
desc = L["OPT_total_d"],
get = "IsShowingTextTotal",
set = "ToggleShowingTextTotal",
},
lastmessage = {
type = 'toggle',
name = L["OPT_lastmessage"],
desc = L["OPT_lastmessage_d"],
get = "IsShowingTextLastMessage",
set = "ToggleShowingTextLastMessage",
},
}
},
levels = {
type = 'group',
name = L["OPT_levels"],
desc = L["OPT_levels_d"],
args = {
game = {
type = "toggle", name = L["OPT_levels_game"],
desc = L["OPT_levels_game_d"],
get = "IsShowingLevelsGame",
set = "ToggleShowingLevelsGame",
},
tablet = {
type = "toggle", name = L["OPT_levels_tablet"],
desc = L["OPT_levels_tablet_d"],
get = "IsShowingLevelsTablet",
set = "ToggleShowingLevelsTablet",
},
zone = {
type = "toggle", name = L["OPT_levels_zone"],
desc = L["OPT_levels_zone_d"],
get = "IsShowingLevelsZone",
set = "ToggleShowingLevelsZone",
},
},
},
diff = {
type = 'toggle',
name = L["OPT_diff"],
desc = L["OPT_diff_d"],
get = "IsShowingDifficulty",
set = "ToggleShowingDifficulty",
},
impossible = {
type = 'toggle',
name = L["OPT_impossible"],
desc = L["OPT_impossible_d"],
get = "IsShowingImpossible",
set = "ToggleShowingImpossible",
},
area = {
type = 'toggle',
name = L["OPT_area"],
desc = L["OPT_area_d"],
get = "IsShowingArea",
set = "ToggleShowingArea",
},
caonly = {
type = 'toggle',
name = L["OPT_caonly"],
desc = L["OPT_caonly_d"],
get = "IsShowingCurrentAreaOnly",
set = "ToggleShowingCurrentAreaOnly",
},
classanyway = {
type = 'toggle',
name = L["OPT_classanyway"],
desc = L["OPT_classanyway_d"],
get = "IsShowingClassAnyway",
set = "ToggleShowingClassAnyway",
},
description = {
type = 'toggle',
name = L["OPT_description"],
desc = L["OPT_description_d"],
get = "IsShowingDescription",
set = "ToggleShowingDescription",
},
cadonly = {
type = 'toggle',
name = L["OPT_cadonly"],
desc = L["OPT_cadonly_d"],
get = "IsShowingCurrentAreaDescriptionOnly",
set = "ToggleShowingCurrentAreaDescriptionOnly",
},
completed= {
type = 'toggle',
name = L["OPT_completed"],
desc = L["OPT_completed_d"],
get = "IsShowingCompletedObjectives",
set = "ToggleShowingCompletedObjectives",
},
tooltip = {
type = 'toggle',
name = L["OPT_tooltip"],
desc = L["OPT_tooltip_d"],
get = "IsShowingInItemTooltip",
set = "ToggleShowingInItemTooltip",
},
colorobj = {
type = 'toggle',
name = L["OPT_colorobj"],
desc = L["OPT_colorobj_d"],
get = "IsColoringObjectives",
set = "ToggleColoringObjectives",
},
wrap = {
type = 'toggle',
name = L["OPT_wrap"],
desc = L["OPT_wrap_d"],
get = "IsWrappingQuests",
set = "ToggleWrappingQuests",
},
}
}
}
}
QuestsFu:RegisterChatCommand({"/questsfu", "/fuq" }, optionsTable)
QuestsFu.OnMenuRequest = optionsTable
function QuestsFu:ToggleShowingTextComplete()
self.db.profile.showTextOpt.complete = not self.db.profile.showTextOpt.complete
self:UpdateText()
return self.db.profile.showTextOpt.complete
end
function QuestsFu:ToggleShowingTextCurrent()
self.db.profile.showTextOpt.current = not self.db.profile.showTextOpt.current
self:UpdateText()
return self.db.profile.showTextOpt.current
end
function QuestsFu:ToggleShowingTextTotal()
self.db.profile.showTextOpt.total = not self.db.profile.showTextOpt.total
self:UpdateText()
return self.db.profile.showTextOpt.total
end
function QuestsFu:ToggleShowingTextLastMessage()
self.db.profile.showTextOpt.lastmessage = not self.db.profile.showTextOpt.lastmessage
self:UpdateText()
return self.db.profile.showTextOpt.lastmessage
end
function QuestsFu:IsShowingTextComplete()
return self.db.profile.showTextOpt.complete
end
function QuestsFu:IsShowingTextCurrent()
return self.db.profile.showTextOpt.current
end
function QuestsFu:IsShowingTextTotal()
return self.db.profile.showTextOpt.total
end
function QuestsFu:IsShowingTextLastMessage()
return self.db.profile.showTextOpt.lastmessage
end
function QuestsFu:IsShowingLevelsGame()
return self.db.profile.showLevelsGame
end
function QuestsFu:IsShowingLevelsTablet()
return self.db.profile.showLevelsTablet
end
function QuestsFu:IsShowingLevelsZone()
return self.db.profile.showLevelsZone
end
function QuestsFu:ToggleShowingLevelsGame(silent)
self.db.profile.showLevelsGame = not self.db.profile.showLevelsGame
if self.db.profile.showLevelsGame then
self:RegisterEvent("GOSSIP_SHOW", "OnGossipShow")
self:RegisterEvent("QUEST_GREETING", "OnQuestGreeting")
self:Hook("GetQuestLogTitle")
else
self:UnregisterEvent("GOSSIP_SHOW", "OnGossipShow")
self:UnregisterEvent("QUEST_GREETING", "OnQuestGreeting")
self:Unhook("GetQuestLogTitle")
end
self:UpdateData()
return self.db.profile.showLevelsGame
end
function QuestsFu:ToggleShowingLevelsTablet(silent)
self.db.profile.showLevelsTablet = not self.db.profile.showLevelsTablet
self:UpdateTooltip()
return self.db.profile.showLevelsTablet
end
function QuestsFu:ToggleShowingLevelsZone(silent)
self.db.profile.showLevelsZone = not self.db.profile.showLevelsZone
self:UpdateTooltip()
return self.db.profile.showLevelsZone
end
function QuestsFu:IsShowingDifficulty()
return self.db.profile.showDifficulty
end
function QuestsFu:ToggleShowingDifficulty(silent)
self.db.profile.showDifficulty = not self.db.profile.showDifficulty
self:UpdateTooltip()
return self.db.profile.showDifficulty
end
function QuestsFu:IsShowingImpossible()
return self.db.profile.showImpossible
end
function QuestsFu:ToggleShowingImpossible(silent)
self.db.profile.showImpossible = not self.db.profile.showImpossible
self:UpdateTooltip()
return self.db.profile.showImpossible
end
function QuestsFu:IsShowingArea()
return self.db.profile.showArea
end
function QuestsFu:ToggleShowingArea(silent)
self.db.profile.showArea = not self.db.profile.showArea
self:UpdateTooltip()
return self.db.profile.showArea
end
function QuestsFu:IsShowingCurrentAreaOnly()
return self.db.profile.showCurrentAreaOnly
end
function QuestsFu:ToggleShowingCurrentAreaOnly(silent)
self.db.profile.showCurrentAreaOnly = not self.db.profile.showCurrentAreaOnly
self:UpdateTooltip()
return self.db.profile.showCurrentAreaOnly
end
function QuestsFu:IsShowingClassAnyway()
return self.db.profile.showClassAnyway
end
function QuestsFu:ToggleShowingClassAnyway(silent)
self.db.profile.showClassAnyway = not self.db.profile.showClassAnyway
self:UpdateTooltip()
return self.db.profile.showClassAnyway
end
function QuestsFu:IsShowingCurrentAreaDescriptionOnly()
return self.db.profile.showCurrentAreaDescriptionOnly
end
function QuestsFu:ToggleShowingCurrentAreaDescriptionOnly(silent)
self.db.profile.showCurrentAreaDescriptionOnly = not self.db.profile.showCurrentAreaDescriptionOnly
self:UpdateTooltip()
return self.db.profile.showCurrentAreaDescriptionOnly
end
function QuestsFu:IsShowingDescription()
return self.db.profile.showDescription
end
function QuestsFu:ToggleShowingDescription(silent)
self.db.profile.showDescription = not self.db.profile.showDescription
self:UpdateTooltip()
return self.db.profile.showDescription
end
function QuestsFu:IsColoringObjectives()
return self.db.profile.colorObjectives
end
function QuestsFu:ToggleColoringObjectives(silent)
self.db.profile.colorObjectives = not self.db.profile.colorObjectives
self:UpdateTooltip()
return self.db.profile.colorObjectives
end
function QuestsFu:IsShowingCompletedObjectives()
return self.db.profile.showCompletedObjectives
end
function QuestsFu:ToggleShowingCompletedObjectives(silent)
self.db.profile.showCompletedObjectives = not self.db.profile.showCompletedObjectives
self:UpdateTooltip()
return self.db.profile.showCompletedObjectives
end
function QuestsFu:IsShowingInItemTooltip()
return self.db.profile.showInItemTooltip
end
function QuestsFu:ToggleShowingInItemTooltip(silent)
self.db.profile.showInItemTooltip = not self.db.profile.showInItemTooltip
self:UpdateTooltip()
return self.db.profile.showInItemTooltip
end
function QuestsFu:IsWrappingQuests()
return self.db.profile.wrapQuests
end
function QuestsFu:ToggleWrappingQuests(silent)
self.db.profile.wrapQuests = not self.db.profile.wrapQuests
self:UpdateTooltip()
return self.db.profile.wrapQuests
end
function QuestsFu:OnInitialize()
if type(self.db.profile.showText) == 'table' then
--FuBarPlugin-2.0 appropriated .showText. Switch it out.
self.db.profile.showTextOps = self.db.profile.showText
self.db.profile.showText = nil
end
self.numQuests = 0
self.numEntries = 0
self.zones = {}
self.zone_quests = {}
self.quests = {}
self.items = {}
self.mobs = {}
self.lastuimessage = ""
self.lastquestmessage = ""
self.allowedToUpdate = true
self.loadedWatchedQuests = false
end
function QuestsFu:OnEnable()
self:RegisterEvent("QUEST_LOG_UPDATE", "OnQuestLogUpdate")
self:RegisterEvent("PLAYER_LEVEL_UP", "UpdateTooltip") -- Quest difficulty colors can change on level; just redraw the tooltip in case they have it open while levelling.
self:RegisterEvent("ZONE_CHANGED_NEW_AREA", "UpdateTooltip")
self:RegisterEvent("UPDATE_MOUSEOVER_UNIT", "OnMouseOverUnit")
self:RegisterEvent("UI_INFO_MESSAGE","OnUIInfoMessage")
self:Hook("ContainerFrameItemButton_OnEnter", "OnItemTooltip")
self:Hook("AddQuestWatch", "OnAddQuestWatch")
self:Hook("RemoveQuestWatch", "OnRemoveQuestWatch")
self:ScheduleEvent(self.LoadWatchedQuests, 1, self)
if self:IsShowingLevelsGame() then
self:RegisterEvent("GOSSIP_SHOW", "OnGossipShow")
self:RegisterEvent("QUEST_GREETING", "OnQuestGreeting")
self:Hook("GetQuestLogTitle")
end
end
function QuestsFu:Disable()
metro:Unregister(self.name)
end
function QuestsFu:MakeTag(level, tag)
if tag then
if tag == L["ELITE"] then tag = L["TAG_ELITE"]
elseif tag == L["DUNGEON"] then tag = L["TAG_DUNGEON"]
elseif tag == L["PVP"] then tag = L["TAG_PVP"]
elseif tag == L["RAID"] then tag = L["TAG_RAID"]
end
else
tag = ''
end
return "[" .. level .. tag .. "] "
end
function QuestsFu:GetQuestLogTitle(index)
local questLogTitleText, level, questTag, isHeader, isCollapsed, isComplete = self.hooks["GetQuestLogTitle"].orig(index)
if not isHeader and level then
if questLogTitleText then
questLogTitleText = self:MakeTag(level, questTag) .. questLogTitleText
end
end
return questLogTitleText, level, questTag, isHeader, isCollapsed, isComplete
end
--This is pretty much how Minimalist does it, which it credits to AutoSelect.
function QuestsFu:OnGossipShow()
local buttonindex = 1
local list, button
if (GetGossipAvailableQuests()) then
list = compost:Acquire(GetGossipAvailableQuests())
for i = 2,getn(list),2 do
button = getglobal("GossipTitleButton"..(buttonindex))
button:SetText(format('[%d] %s',list[i],list[i-1]))
buttonindex = buttonindex + 1
end
buttonindex = buttonindex + 1
compost:Reclaim(list)
end
if (GetGossipActiveQuests()) then
list = compost:Acquire(GetGossipActiveQuests())
for i = 2,getn(list),2 do
button = getglobal("GossipTitleButton"..(buttonindex))
button:SetText(format('[%d] %s',list[i],list[i-1]))
buttonindex = buttonindex + 1
end
compost:Reclaim(list)
end
end
--This is pretty much how Minimalist does it, which it credits to AutoSelect.
function QuestsFu:OnQuestGreeting()
local numactive,numavailable = GetNumActiveQuests(), GetNumAvailableQuests()
local title, level, button
local o,GetTitle,GetLevel = 0,GetActiveTitle,GetActiveLevel
for i=1, numactive + numavailable do
if i == numactive + 1 then
o,GetTitle,GetLevel = numactive,GetAvailableTitle,GetAvailableLevel
end
title,level = GetTitle(i-o), GetLevel(i-o)
button = getglobal("QuestTitleButton"..i)
button:SetText(format('[%d] %s',level,title))
end
end
function QuestsFu:OnAddQuestWatch(id)
self.hooks["AddQuestWatch"].orig(id)
self:SaveWatchedQuests()
end
function QuestsFu:OnRemoveQuestWatch(id)
self.hooks["RemoveQuestWatch"].orig(id)
self:SaveWatchedQuests()
end
function QuestsFu:OnUIInfoMessage()
self.lastuimessage = arg1
self:ScheduleEvent(self.ClearUIInfoMessage, 0.5, self)
end
function QuestsFu:ClearUIInfoMessage()
self.lastuimessage = ""
end
function QuestsFu:OnQuestLogUpdate()
if self.allowedToUpdate then self.lastquestmessage = self.lastuimessage end
self.allowedToUpdate = false
self:ScheduleEvent("ThrottleUpdate", function(self)
self.allowedToUpdate = true
self:Update()
end, 1, self)
end
function QuestsFu:OnMouseOverUnit()
-- Make sure that this is wanted, and that the tooltip is actually read/writeable.
if self:IsShowingInItemTooltip() and self:CanMessWithGameTooltip() then
--Comes with color codes. Strip 'em out.
local thisMob = string.gsub(getglobal('GameTooltipTextLeft1'):GetText(),"|c........(.*)|?r?","%1")
if self.mobs[thisMob] then
self:AddToGameTooltipAndFixHeight(self.mobs[thisMob].quest..": "..self.mobs[thisMob].needed, self.mobs[thisMob].colorr, self.mobs[thisMob].colorg, self.mobs[thisMob].colorb)
end
end
end
function QuestsFu:OnItemTooltip()
self.hooks["ContainerFrameItemButton_OnEnter"].orig()
if self:IsShowingInItemTooltip() and self:CanMessWithGameTooltip() then
--Comes with color codes. Strip 'em out.
local thisItem = string.gsub(getglobal('GameTooltipTextLeft1'):GetText(),"|c........(.*)|r","%1")
if self.items[thisItem] then
self:AddToGameTooltipAndFixHeight(self.items[thisItem].quest..": "..self.items[thisItem].needed, self.items[thisItem].colorr, self.items[thisItem].colorg, self.items[thisItem].colorb)
end
end
end
function QuestsFu:CanMessWithGameTooltip()
if GameTooltip and getglobal('GameTooltipTextLeft1'):IsVisible() and getglobal('GameTooltipTextLeft1'):GetText() ~= nil then
return true
else
return false
end
end
function QuestsFu:AddToGameTooltipAndFixHeight(text, r, g, b)
GameTooltip:AddLine(text, r, g, b)
-- Fix up the width of the tooltip
length = getglobal(GameTooltip:GetName() .. "TextLeft" .. GameTooltip:NumLines()):GetStringWidth()
-- Space for right-border:
length = length + 22
GameTooltip:SetHeight(GameTooltip:GetHeight() + 14)
if length > GameTooltip:GetWidth() then
GameTooltip:SetWidth(length)
end
end
function QuestsFu:OnDataUpdate()
--UpdateText and UpdateTooltip both need to know things about the questlog. Better to do this once.
compost:Reclaim(self.quests, 3)
compost:Reclaim(self.zone_quests, 1)
self.quests, self.zone_quests = nil, nil
local startingQuestLogSelection = GetQuestLogSelection()
local numEntries, numQuests = GetNumQuestLogEntries()
local numQuestsDone = 0
local quests = compost:Acquire()
local zones = compost:Erase(self.zones)
--LEVELS--local level_quests = {}
local zone_quests = compost:Acquire()
local items = compost:Erase(self.items)
local mobs = compost:Erase(self.mobs)
local zoneIndex = "OMG NONE" --The first item in the quest log should always be a header, so this should always be replaced. But just in case.
if numEntries > 0 and self.allowedToUpdate then
local questid
for questid = 1, numEntries do
local strQuestLogTitleText, strQuestLevel, strQuestTag, isHeader, isCollapsed, isComplete = GetQuestLogTitle(questid)
local q = compost:Acquire()
if isHeader then
zoneIndex = strQuestLogTitleText
table.insert(zones, zoneIndex)
zone_quests[zoneIndex] = compost:Acquire()
else
q.zone = zoneIndex
q.tag = strQuestTag
SelectQuestLogEntry(questid)
if isComplete == 1 then
isComplete = L["QUEST_DONE"]
numQuestsDone = numQuestsDone + 1
elseif isComplete == -1 then
isComplete = L["QUEST_FAILED"]
else
isComplete = nil
end
q.title = strQuestLogTitleText
q.level = strQuestLevel
q.complete = isComplete
local lb = compost:Acquire()
if GetNumQuestLeaderBoards() > 0 then
local ii
for ii=1, GetNumQuestLeaderBoards() do
local desc, qtype, done = GetQuestLogLeaderBoard(ii)
local itemName,mobName,numNeeded,numItems,factionName,factionCurrent,factionNeeded
if qtype == 'item' then
itemName,numItems,numNeeded = deformat(desc, QUEST_OBJECTS_FOUND)
desc = itemName
elseif qtype == 'monster' then
mobName,numItems,numNeeded = deformat(desc, QUEST_MONSTERS_KILLED)
if mobName == nil or numItems == nil or numNeeded == nil then
--Sometimes we get objectives like "Find Mankrik's Wife: 0/1", which are listed as "monster".
mobName, numItems, numNeeded = deformat(desc, QUEST_OBJECTS_FOUND)
end
desc = mobName
elseif qtype == 'reputation' then
factionName,factionCurrent,factionNeeded = deformat(desc, QUEST_FACTION_NEEDED)
numItems = self:GetReactionLevel(factionCurrent)
numNeeded = self:GetReactionLevel(factionNeeded)
desc = factionName
end
local r,g,b
if numItems ~= nil then
-- This quest involves items!
r, g, b = crayon:GetThresholdColor(numItems / numNeeded)
end
if qtype == 'item' then
items[itemName] = compost:AcquireHash('quest', strQuestLogTitleText, 'item', itemName, 'needed', string.format("%s/%s",numItems,numNeeded), 'colorr', r, 'colorg', g, 'colorb', b)
elseif qtype == 'monster' then
mobs[mobName] = compost:AcquireHash('quest', strQuestLogTitleText, 'mob', mobName, 'needed', string.format("%s/%s",numItems,numNeeded), 'colorr', r, 'colorg', g, 'colorb', b)
end
if done then
done = L["QUEST_DONE"]
elseif numItems and numNeeded then
if qtype == 'reputation' then
done = string.format("%s/%s",factionCurrent,factionNeeded)
else
done = string.format("%s/%s",numItems,numNeeded)
end
else
--I think this shouldn't happen. ...but I haven't seen every quest out there.
done = ""
end
table.insert(lb, compost:AcquireHash('description', desc, 'done', done, 'colorr', r, 'colorg', g, 'colorb', b))
end
else
local strQuestDescription, strQuestObjectives = GetQuestLogQuestText(questid)
--q.objective = self.superwrap(strQuestObjectives, 50, 0, 2)
q.objective = strQuestObjectives
end
q.leaderboard = lb
q.id = questid
quests[questid] = q
table.insert(zone_quests[zoneIndex], questid)
--LEVELS--table.insert(level_quests[tonumber(strQuestLevel)], questid)
end
end
end
self.quests = quests
self.zones = zones
--LEVELS--self.level_quests = level_quests
self.zone_quests = zone_quests
self.items = items
self.mobs = mobs
self.numQuests = numQuests
self.numEntries = numEntries
self.numQuestsDone = numQuestsDone
SelectQuestLogEntry(startingQuestLogSelection)
self:SaveWatchedQuests() --A watched quest may have gone away because of the update. (The game doesn't call RemoveQuestWatch for it...)
end
function QuestsFu:OnTextUpdate()
local text = ""
local maxQuests = 20
if self.allowedToUpdate then
local r,g,b = GameFontNormal:GetTextColor()
local color = string.format("%02X%02X%02X", r * 255, g * 255, b * 255)
if self:IsShowingTextComplete() then
color = crayon:GetThresholdHexColor(self.numQuestsDone / self.numQuests)
text = text .. crayon:Colorize(color,self.numQuestsDone)
end
if self:IsShowingTextComplete() and (self:IsShowingTextCurrent() or self:IsShowingTextTotal()) then
text = text .. crayon:Colorize(color,"/")
end
if self:IsShowingTextCurrent() then
color = crayon:GetThresholdHexColor((maxQuests - self.numQuests) / maxQuests)
text = text .. crayon:Colorize(color,self.numQuests)
end
if self:IsShowingTextCurrent() and self:IsShowingTextTotal() then
text = text .. crayon:Colorize(color,"/")
end
if self:IsShowingTextTotal() then
text = text .. crayon:Colorize(color,maxQuests)
end
if (self:IsShowingTextTotal() or self:IsShowingTextComplete() or self:IsShowingTextCurrent()) and self:IsShowingTextLastMessage() and self.lastquestmessage ~= "" then
text = text .. " m: "
end
if self:IsShowingTextLastMessage() and self.lastquestmessage ~= "" then
text = text .. self.lastquestmessage
end
else
text = L["TEXT_LOADING"]
end
self:SetText(text)
end
function QuestsFu:OnTooltipUpdate()
if self.numQuests > 0 and self.allowedToUpdate then
if table.getn(self.zones) then
local currentZone = GetZoneText()
local zonename, zone
local cat
if not self:IsShowingArea() then
cat = tablet:AddCategory('columns', 2)
local sortedQuests = self:SortQuests(self.quests)
for _,quest in sortedQuests do
self:AddQuestToTooltip(cat, quest, true)
end
compost:Reclaim(sortedQuests)
else
for _,zone in self.zones do
-- If showing area headers and either not showing only the current area's quests or this is the current area.
if self:IsShowingArea() and ((currentZone == zone) or not self:IsShowingCurrentAreaOnly() or (self:IsShowingClassAnyway() and UnitClass("player") == zone)) then
local r,g,b = 0.749,1,0.749
zonename = zone
if zone == UnitClass("player") then
r, g, b = babbleclass:GetColor(zone)
else
if self:IsShowingLevelsZone() and tourist:IsZoneOrInstance(zone) then
local high, low = tourist:GetLevel(zone)
if high > 0 and low > 0 then
zonename = string.format("%s (%d-%d)", zone, high, low)
end
end
if self:IsShowingDifficulty() and tourist:IsZoneOrInstance(zone) then
r, g, b = tourist:GetLevelColor(zone)
end
end
cat = tablet:AddCategory(
'id', zone,
'text', zonename,
'columns', 2,
'hideBlankLine', true,
'showWithoutChildren', true,
'checked', true, 'hasCheck', true, 'checkIcon', self.db.char.hidden[zone] and "Interface\\Buttons\\UI-PlusButton-Up" or "Interface\\Buttons\\UI-MinusButton-Up",
'func', 'ToggleCategory', 'arg1', self, 'arg2', zone,
'textR', r,
'textG', g,
'textB', b,
'child_func', 'QuestClick',
'child_arg1', self
)
end
-- If we're not hiding the zone and it's either the current zone or we're not showing only the current zone.
if (not self.db.char.hidden[zone]) and ((not self:IsShowingCurrentAreaOnly()) or (currentZone == zone) or (self:IsShowingClassAnyway() and UnitClass("player") == zone)) and (table.getn(self.zone_quests[zone]) > 0) then
local questid
for _,questid in self.zone_quests[zone] do
self:AddQuestToTooltip(cat, self.quests[questid], false)
end
end
end
end
end
end
tablet:SetHint(L["TOOLTIP_HINT"])
end
function QuestsFu:MembersOnQuest(questid)
--Return the number of party members on a quest. Returns zero if not in a party.
local n = 0
local party = GetNumPartyMembers()
if party > 0 then
for i = 1,party do
n = n + (IsUnitOnQuest(questid, "party"..i) and 1 or 0)
end
end
return n
end
function QuestsFu:AddQuestToTooltip(cat, quest, appendZone)
--Are we hiding impossible quests, and is this quest impossible?
local questImpossible = (GetDifficultyColor(quest.level) == QuestDifficultyColor.impossible)
if not questImpossible or (questImpossible and self:IsShowingImpossible()) then
local thisQuest, thisQuestColor
local questLevel, questZone = "",""
local currentZone = GetZoneText()
local questShared = QuestsFu:MembersOnQuest(quest.id)
if questShared == 0 then
questShared = ""
end
if appendZone then
questZone = format(" (%s)", quest.zone)
end
if self:IsShowingLevelsTablet() and not self:IsShowingLevelsGame() then
questLevel = self:MakeTag(quest.level, quest.tag)
end
thisQuest = questLevel..quest.title..questZone..((questShared ~= "") and "|c0000ff00<"..questShared..">|r" or '')
if self:IsShowingDifficulty() then
thisQuestColor = GetDifficultyColor(quest.level)
end
cat:AddLine(
'text', thisQuest, 'wrap', self:IsWrappingQuests(),
'text2', quest.complete,
'textR', (thisQuestColor and thisQuestColor.r) or 1, 'textG', (thisQuestColor and thisQuestColor.g) or 1, 'textB', (thisQuestColor and thisQuestColor.b) or 1,
'text2R', (quest.complete == L["QUEST_FAILED"]) and 1 or 0, 'text2G', (quest.complete == L["QUEST_DONE"]) and 1 or 0, 'text2B', 0,
'func', 'QuestClick',
'arg1', self,
'arg2', quest.id,
'indentation', 6,
'checked', IsQuestWatched(quest.id),
'hasCheck', IsQuestWatched(quest.id)
)
-- If we're showing descriptions/objectives and it's either the current zone or we're not showing descriptions only for the current zone.
if self:IsShowingDescription() and ((currentZone == quest.zone) or not self:IsShowingCurrentAreaDescriptionOnly()) then
-- If we know of leaderboard objectives:
if table.getn(quest.leaderboard) > 0 then
local i, goal
for i,goal in quest.leaderboard do
if not (goal.done == L["QUEST_DONE"] and not self:IsShowingCompletedObjectives()) then
local r,g,b
if self:IsColoringObjectives() then
r,g,b = goal.colorr, goal.colorg, goal.colorb
end
cat:AddLine(
'text', ' '..goal.description,
'text2', goal.done,
'textR', r or ((thisQuestColor and thisQuestColor.r) or 1), 'textG', g or ((thisQuestColor and thisQuestColor.g) or 1), 'textB', b or ((thisQuestColor and thisQuestColor.b) or 1),
'text2R', r or ((thisQuestColor and thisQuestColor.r) or 1), 'text2G', g or ((thisQuestColor and thisQuestColor.g) or 1), 'text2B', b or ((thisQuestColor and thisQuestColor.b) or 1),
'size', tablet:GetNormalFontSize()-2, 'size2', tablet:GetNormalFontSize()-2,
'arg2', quest.id,
'indentation', 12
)
end
end
-- Otherwise, if the quest is incomplete (or complete and we're showing completed objectives), add the generic objective.
elseif not (quest.complete and not self:IsShowingCompletedObjectives()) then
cat:AddLine(
'text', quest.objective,
'wrap', true,
'textR', (thisQuestColor and thisQuestColor.r) or 1,
'textG', (thisQuestColor and thisQuestColor.g) or 1,
'textB', (thisQuestColor and thisQuestColor.b) or 1,
'size', tablet:GetNormalFontSize()-2,
'arg2', quest.id,
'indentation', 12
)
end
end
end
end
function QuestsFu:ToggleCategory(id, button)
if self.db.char.hidden[id] then
self.db.char.hidden[id] = false
else
self.db.char.hidden[id] = true
end
-- Refresh in place
self:UpdateTooltip()
end
--TheFly contributed the base of this, and it's still using much of the logic he provided
function QuestsFu:QuestClick(questid, button)
if IsAltKeyDown() then
-- Shift-click toggles quest-watch on this quest.
if IsQuestWatched(questid) then
RemoveQuestWatch(questid)
QuestWatch_Update()
else
-- Set error if no objectives
if GetNumQuestLeaderBoards(questid) == 0 then
UIErrorsFrame:AddMessage(QUEST_WATCH_NO_OBJECTIVES, 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME)
return
end
-- Set an error message if trying to show too many quests
if GetNumQuestWatches() >= MAX_WATCHABLE_QUESTS then
UIErrorsFrame:AddMessage(format(QUEST_WATCH_TOO_MANY, MAX_WATCHABLE_QUESTS), 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME)
return
end
AddQuestWatch(questid)
QuestWatch_Update()
end
elseif IsShiftKeyDown() and IsControlKeyDown() and ChatFrameEditBox:IsVisible() then
-- Add the quest objectives to the chat editbox, if it's open.
for i,goal in pairs(self.quests[questid].leaderboard) do
ChatFrameEditBox:Insert(string.format("{%s %s} ", goal.description, goal.done))
end
elseif IsShiftKeyDown() and ChatFrameEditBox:IsVisible() then
-- Add quest title to the chat editbox if it's open.
ChatFrameEditBox:Insert(self.quests[questid].title)
elseif IsControlKeyDown() then
-- Share the quest with party members.
local wasSelected = GetQuestLogSelection()
SelectQuestLogEntry(questid)
if (GetQuestLogPushable() and GetNumPartyMembers() > 0) then
QuestLogPushQuest()
end
SelectQuestLogEntry(questid)
else
if QuestLogFrame:IsVisible() then
if self.lastIndex == questid then
HideUIPanel(QuestLogFrame)
end
else
ShowUIPanel(QuestLogFrame)
end
if (self.numEntries > QUESTS_DISPLAYED) then
if (questid < self.numEntries - QUESTS_DISPLAYED) then
FauxScrollFrame_SetOffset(QuestLogListScrollFrame, questid - 1)
QuestLogListScrollFrameScrollBar:SetValue((questid - 1) * QUESTLOG_QUEST_HEIGHT)
else
FauxScrollFrame_SetOffset(QuestLogListScrollFrame, self.numEntries - QUESTS_DISPLAYED)
QuestLogListScrollFrameScrollBar:SetValue((self.numEntries - QUESTS_DISPLAYED) * QUESTLOG_QUEST_HEIGHT)
end
end
SelectQuestLogEntry(questid)
QuestLog_SetSelection(questid)
self.lastIndex = questid
end
end
function QuestsFu:OnClick()
ToggleQuestLog()
end
function QuestsFu:GetReactionLevel(leveltext)
if leveltext == FACTION_STANDING_LABEL1 then --Hated
return 1
elseif leveltext == FACTION_STANDING_LABEL2 then --Hostile
return 2
elseif leveltext == FACTION_STANDING_LABEL3 then --Unfriendly
return 3
elseif leveltext == FACTION_STANDING_LABEL4 then --Neutral
return 4
elseif leveltext == FACTION_STANDING_LABEL5 then --Friendly
return 5
elseif leveltext == FACTION_STANDING_LABEL6 then --Honored
return 6
elseif leveltext == FACTION_STANDING_LABEL7 then --Revered
return 7
elseif leveltext == FACTION_STANDING_LABEL8 then --Exalted
return 8
end
end
function QuestsFu:LoadWatchedQuests()
if not (GetNumQuestWatches() > 0) then
for _,questId in self.db.char.watchedQuests do
AddQuestWatch(questId)
end
end
QuestWatch_Update()
self.loadedWatchedQuests = true
end
function QuestsFu:SaveWatchedQuests()
if self.loadedWatchedQuests then
self.db.char.watchedQuests = compost:Erase(self.db.char.watchedQuests)
for i = 1, GetNumQuestWatches() do
table.insert(self.db.char.watchedQuests, GetQuestIndexForWatch(i))
end
end
end
-- Sorts a table of quests by level, with quests of the same level ordered
-- by elite, dungeon or raid tags, i.e. normal < elite < dungeon < raid.
-- Quests of the same level and tag are sorted alphabetically by title.
-- Returns a new table of the sorted quests. Original table is unchanged.
function QuestsFu:SortQuests(quests)
-- Make a copy of the table, without keys
local sortedQuests = compost:Acquire()
table.foreach(self.quests,
function(k,v)
table.insert(sortedQuests, v)
end
)
table.sort(sortedQuests,
function(a,b)
local aa = a.level*4
local bb = b.level*4
if a.tag == L["TAG_ELITE"] then aa = aa+1 end
if a.tag == L["TAG_DUNGEON"] then aa = aa+2 end
if a.tag == L["TAG_RAID"] then aa = aa+3 end
if b.tag == L["TAG_ELITE"] then bb = bb+1 end
if b.tag == L["TAG_DUNGEON"] then bb = bb+2 end
if b.tag == L["TAG_RAID"] then bb = bb+3 end
if aa == bb then
return a.title < b.title
end
return aa < bb;
end
)
return sortedQuests
end