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