--------------------------------------------------------------------------------------------------- -- Name: QuestieNotes -- Description: Handles all the quest map notes --------------------------------------------------------------------------------------------------- --///////////////////////////////////////////////////////////////////////////////////////////////-- --------------------------------------------------------------------------------------------------- -- Local Vars --------------------------------------------------------------------------------------------------- local AllFrames = {}; local FramePool = {}; local Cluster = {}; local LastContinent = nil; local LastZone = nil; local Dewdrop = AceLibrary("Dewdrop-2.0"); local specialSources = { ["openedby"] = 1, }; local QGet_QuestLogTitle = GetQuestLogTitle; local QGet_NumQuestLeaderBoards = GetNumQuestLeaderBoards; local QSelect_QuestLogEntry = SelectQuestLogEntry; local QGet_QuestLogLeaderBoard = GetQuestLogLeaderBoard; local QGet_QuestLogQuestText = GetQuestLogQuestText; local QGet_TitleText = GetTitleText; local QGet_QuestLogSelection = GetQuestLogSelection; --------------------------------------------------------------------------------------------------- -- Global Vars --------------------------------------------------------------------------------------------------- QUESTIE_NOTES_MAP_ICON_SCALE = 1.2; QUESTIE_NOTES_WORLD_MAP_ICON_SCALE = 0.75; QUESTIE_NOTES_CONTINENT_ICON_SCALE = 1; QUESTIE_NOTES_MINIMAP_ICON_SCALE = 1.0; QuestieMapNotes = {}; QuestieUsedNoteFrames = {}; QuestieHandledQuests = {}; QuestieAvailableMapNotes = {}; QuestieCachedMonstersAndObjects = {}; Questie_LastTooltip = GetTime(); QUESTIE_DEBUG_TOOLTIP = nil; Questie_TooltipCache = {}; CREATED_NOTE_FRAMES = 1; INIT_POOL_SIZE = 11; Cluster.__index = Cluster; __TT_LineCache = {}; UIOpen = false; QuestieNotes = AceLibrary("AceAddon-2.0"):new("AceHook-2.1") --------------------------------------------------------------------------------------------------- --Setup Hooks --------------------------------------------------------------------------------------------------- function QuestieNotes:OnInitialize() self:Hook(WorldMapFrame, "Show", "WorldMapFrame_Show", true) self:Hook(WorldMapFrame, "SetAlpha", "WorldMapFrame_SetAlpha", true) end --------------------------------------------------------------------------------------------------- -- Refreshes Quest Notes --------------------------------------------------------------------------------------------------- function Questie:RefreshQuestNotes() QUESTIE_UPDATE_EVENT = 1; if (GetTime() - QUESTIE_LAST_SYNCLOG > 0.1) then Questie:AddEvent("SYNCLOG", 0); QUESTIE_LAST_SYNCLOG = GetTime(); else QUESTIE_LAST_SYNCLOG = GetTime(); end if (GetTime() - QUESTIE_LAST_DRAWNOTES > 0.1) then Questie:AddEvent("DRAWNOTES", 0.2); QUESTIE_LAST_DRAWNOTES = GetTime(); else QUESTIE_LAST_DRAWNOTES = GetTime(); end if (GetTime() - QUESTIE_LAST_TRACKER > 0.1) then Questie:AddEvent("TRACKER", 0.4); QUESTIE_LAST_TRACKER = GetTime(); else QUESTIE_LAST_TRACKER = GetTime(); end end --------------------------------------------------------------------------------------------------- -- Adds quest notes to map --------------------------------------------------------------------------------------------------- function Questie:AddQuestToMap(questHash, redraw) if(IsQuestieActive == false) then return; end if questHash == -1 then return; end --Questie:debug_Print("Notes:AddQuestToMap --> Adding Quest to Map [Hash: "..questHash.."]"); local c, z = GetCurrentMapContinent(), GetCurrentMapZone(); Questie:RemoveQuestFromMap(questHash); local objectives = Questie:GetQuestObjectivePaths(questHash) --Cache code local ques = {}; ques["noteHandles"] = {}; UsedContinents = {}; UsedZones = {}; local Quest = Questie:IsQuestFinished(questHash); if not (Quest) then Questie:debug_Print("Notes:AddQuestToMap --> Display Objective Icons: [Hash: "..questHash.."]"); for objectiveid, objective in pairs(objectives) do if not objective.done then local typeToIcon = { ["item"] = "loot", ["event"] = "event", ["monster"] = "slay", ["object"] = "object", }; local defaultIcon = typeToIcon[objective.type]; local iconMeta = { ["defaultIcon"] = defaultIcon }; Questie:RecursiveCreateNotes(c, z, questHash, objective.path, iconMeta, objectiveid); end end else --Questie:debug_Print("Notes:AddQuestToMap --> Display Finished Quest Icon: [Hash: "..questHash.."]"); local addedNote = false local questInfo = QuestieHashMap[Quest.questHash]; if questInfo ~= nil then local typeFunctions = { ['monster'] = GetMonsterLocations, ['object'] = GetObjectLocations, ['unknown'] = function() return nil; end }; local typeFunction = typeFunctions[questInfo.finishedType]; local finishPath = typeFunction(questInfo.finishedBy); if finishPath == nil or (not next(finishPath)) then finishPath = typeFunction(QuestieFinishers[Quest.name]); end if(finishPath) then local locations = Questie:RecursiveGetPathLocations(finishPath); if next(locations) then for i, location in pairs(locations) do local c, z, x, y = location[1], location[2], location[3], location[4]; Questie:AddNoteToMap(c, z, x, y, "complete", questHash, 0); addedNote = true end end end end if addedNote == false then Questie:debug_Print("AddQuestToMap: ERROR Quest broken! ", Quest["name"], questHash, "report on github!") end end --Cache code ques["objectives"] = objectives; QuestieHandledQuests[questHash] = ques; if (redraw) then Questie:debug_Print("Notes:AddQuestToMap: redraw VAR true --> Questie:RefreshQuestStatus();"); Questie:RefreshQuestNotes(); end end --------------------------------------------------------------------------------------------------- -- Checks for a quest note in QuestieMapNotes --------------------------------------------------------------------------------------------------- function Questie:CheckQuestNote(questHash) for continent, zoneTable in pairs(QuestieMapNotes) do for index, zone in pairs(zoneTable) do for i, note in pairs(zone) do if (note.questHash == questHash) then return true end end end end return false end --------------------------------------------------------------------------------------------------- -- Updates quest notes on map --------------------------------------------------------------------------------------------------- function Questie:UpdateQuestNotes(questHash, redraw) if not QuestieHandledQuests[questHash] then --Questie:debug_Print("UpdateQuestNotes: ERROR! Tried updating a quest not handled. Hash: ", questHash); return; end local prevQuestLogSelection = QGet_QuestLogSelection() local QuestLogID = Questie:GetQuestIdFromHash(questHash); QSelect_QuestLogEntry(QuestLogID); local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(QuestLogID); local count = QGet_NumQuestLeaderBoards(); local questText, objectiveText = QGet_QuestLogQuestText(); for k, noteInfo in pairs(QuestieHandledQuests[questHash]["noteHandles"]) do for id, note in pairs(QuestieMapNotes[noteInfo.c][noteInfo.z]) do if(note.questHash == questHash) then local desc, typ, done = QGet_QuestLogLeaderBoard(note.objectiveid); --Questie:debug_Print("UpdateQuestNotes: Desc: "..tostring(desc).." Type: "..tostring(typ).." Done: "..tostring(done)); end end end QSelect_QuestLogEntry(prevQuestLogSelection) if(redraw) then Questie:debug_Print("Notes:UpdateQuestNotes: redraw VAR true --> Questie:RefreshQuestStatus();"); Questie:RefreshQuestNotes(); end end --------------------------------------------------------------------------------------------------- -- Remove quest note from map --------------------------------------------------------------------------------------------------- function Questie:RemoveQuestFromMap(questHash, redraw) local removed = false; for continent, zoneTable in pairs(QuestieMapNotes) do for index, zone in pairs(zoneTable) do for i, note in pairs(zone) do if(note.questHash == questHash) then QuestieMapNotes[continent][index][i] = nil; removed = true; end end end end if(redraw) then Questie:debug_Print("Notes:RemoveQuestFromMap: redraw VAR true --> Questie:RefreshQuestStatus();"); Questie:RefreshQuestNotes(); end if(QuestieHandledQuests[questHash]) then QuestieHandledQuests[questHash] = nil; end end --------------------------------------------------------------------------------------------------- function Questie:GetMapInfoFromID(id) return QuestieZoneIDLookup[id]; end --------------------------------------------------------------------------------------------------- -- Add quest note to map --------------------------------------------------------------------------------------------------- function Questie:AddNoteToMap(continent, zoneid, posx, posy, type, questHash, objectiveid, path) if (not type == "complete") then return; end if(QuestieMapNotes[continent] == nil) then QuestieMapNotes[continent] = {}; end if(QuestieMapNotes[continent][zoneid] == nil) then QuestieMapNotes[continent][zoneid] = {}; end Note = {}; Note.x = posx; Note.y = posy; Note.zoneid = zoneid; Note.continent = continent; Note.icontype = type; Note.questHash = questHash; Note.objectiveid = objectiveid; Note.path = path table.insert(QuestieMapNotes[continent][zoneid], Note); end --------------------------------------------------------------------------------------------------- -- Add available quest note to map --------------------------------------------------------------------------------------------------- function Questie:AddAvailableNoteToMap(continent, zoneid, posx, posy, type, questHash, objectiveid, path) --This is to set up the variables if(QuestieAvailableMapNotes[continent] == nil) then QuestieAvailableMapNotes[continent] = {}; end if(QuestieAvailableMapNotes[continent][zoneid] == nil) then QuestieAvailableMapNotes[continent][zoneid] = {}; end --Sets values that i want to use for the notes THIS IS WIP MORE INFO MAY BE NEDED BOTH IN PARAMETERS AND NOTES!!! Note = {}; Note.x = posx; Note.y = posy; Note.zoneid = zoneid; Note.continent = continent; Note.icontype = type; Note.questHash = questHash; Note.objectiveid = objectiveid; Note.path = path --Inserts it into the right zone and continent for later use. table.insert(QuestieAvailableMapNotes[continent][zoneid], Note); end --------------------------------------------------------------------------------------------------- -- Gets a blank frame either from Pool or creates a new one! --------------------------------------------------------------------------------------------------- function Questie:GetBlankNoteFrame(frame) if(table.getn(FramePool)==0) then Questie:CreateBlankFrameNote(frame); end f = FramePool[1]; table.remove(FramePool, 1); return f; end --------------------------------------------------------------------------------------------------- -- Hook World Map Events --------------------------------------------------------------------------------------------------- function QuestieNotes:SetAllNoteFramesAlpha() for i,v in ipairs({WorldMapFrame:GetChildren()}) do if v:GetName() and string.find(v:GetName(), "^QuestieNoteFrame") then v:SetAlpha(1) end end end function QuestieNotes:WorldMapFrame_Show(this) self.hooks[this].Show(this) QuestieNotes:SetAllNoteFramesAlpha() end function QuestieNotes:WorldMapFrame_SetAlpha(this, alpha) self.hooks[this].SetAlpha(this, alpha) QuestieNotes:SetAllNoteFramesAlpha() end --------------------------------------------------------------------------------------------------- -- Hook Tooltip --------------------------------------------------------------------------------------------------- function Questie:hookTooltip() local f = GameTooltip:GetScript("OnShow"); --Proper tooltip hooking! if not f then GameTooltip:SetScript("OnShow", function(self) Questie:Tooltip(self, true); end) end local Blizz_GameTooltip_Show = GameTooltip.Show; GameTooltip.Show = function(self) Questie:Tooltip(self); Blizz_GameTooltip_Show(self); end local Bliz_GameTooltip_SetLootItem = GameTooltip.SetLootItem; GameTooltip.SetLootItem = function(self, slot) Bliz_GameTooltip_SetLootItem(self, slot); Questie:Tooltip(self, true); end local index = self:GetID(); local Bliz_GameTooltip_SetQuestLogItem = GameTooltip.SetQuestLogItem; GameTooltip.SetQuestLogItem = function(self, type, index) local link = GetQuestLogItemLink(type, index); if link then Bliz_GameTooltip_SetQuestLogItem(self, type, index); end end end --------------------------------------------------------------------------------------------------- -- Tooltip code for quest objects --------------------------------------------------------------------------------------------------- function Questie:hookTooltipLineCheck() local oh = GameTooltip:GetScript("OnHide"); GameTooltip:SetScript("OnHide", function(self, arg) if oh then oh(self, arg); end __TT_LineCache = {}; end) GameTooltip.AddLine_orig = GameTooltip.AddLine; GameTooltip.AddLine = function(self, line, r, g, b, wrap, lineNumber) GameTooltip:AddLine_orig(line, r, g, b, wrap); if (line) then if lineNumber == nil then lineNumber = 1; end __TT_LineCache[lineNumber] = {}; __TT_LineCache[lineNumber][line] = true; end end end --------------------------------------------------------------------------------------------------- function Questie:Tooltip(this, forceShow, bag, slot) if (QuestieConfig.showToolTips == false) then return end -- Don't show detailed tooltip for questie minimap icons local owner = GameTooltip.owner if owner and owner.type == "MiniMapNote" then return end local monster = UnitName("mouseover") local objective = GameTooltipTextLeft1:GetText() local cacheKey = ""-- .. monster .. objective local validKey = false if(monster) then cacheKey = cacheKey .. monster validKey = true end if(objective) then cacheKey = cacheKey .. objective validKey = true end if not validKey then return end local reaction = UnitReaction("mouseover", "player") local unitColorRGB = Questie:GetReactionColor(reaction) local unitColor = "ff"..fRGBToHex(unitColorRGB.r, unitColorRGB.g, unitColorRGB.b) if (Questie_TooltipCache[cacheKey] == nil) or (QUESTIE_LAST_UPDATE_FINISHED - Questie_TooltipCache[cacheKey]['updateTime']) > 0 then -- Create or Update Tooltip Cache Questie_TooltipCache[cacheKey] = {} Questie_TooltipCache[cacheKey]['lines'] = {} Questie_TooltipCache[cacheKey]['lineCount'] = 1 Questie_TooltipCache[cacheKey]['updateTime'] = GetTime() local prevQuestLogSelection = QGet_QuestLogSelection() for questHash, quest in pairs(QuestieHandledQuests) do local QuestLogID = Questie:GetQuestIdFromHash(questHash) QSelect_QuestLogEntry(QuestLogID) local drawnQuestTitle = false for objectiveid, objectiveInfo in pairs(quest.objectives) do local highlightInfo = { ["text"] = objective, ["color"] = unitColor } local sourceNames = Questie:RecursiveGetSourceNamesFromRawPath(objectiveInfo.path) if objectiveInfo.name == objective or sourceNames[objective] then local lineIndex = Questie_TooltipCache[cacheKey]['lineCount'] if drawnQuestTitle == false then local questInfo = QuestieHashMap[questHash] local colorString = "|c" .. QuestieTracker:GetDifficultyColor(questInfo.questLevel) local title = colorString title = title .. "[" .. questInfo.questLevel .. "] " title = title .. questInfo.name .. "|r" Questie_TooltipCache[cacheKey]['lines'][lineIndex] = { ['color'] = {1,1,1}, ['data'] = " " } lineIndex = lineIndex + 1 Questie_TooltipCache[cacheKey]['lines'][lineIndex] = { ['color'] = {1,1,1}, ['data'] = title, ['wrap'] = false } lineIndex = lineIndex + 1 drawnQuestTitle = true end local desc, type, done = QGet_QuestLogLeaderBoard(objectiveid) if done then Questie_TooltipCache[cacheKey]['lines'][lineIndex] = { ['color'] = {0.2,1,0.3}, ['data'] = desc, ['wrap'] = false } lineIndex = lineIndex + 1 Questie_TooltipCache[cacheKey]['lineCount'] = lineIndex else local objectivePath = deepcopy(objectiveInfo.path) Questie:PostProcessIconPath(objectivePath) local lines = Questie:GetTooltipLines(objectivePath, 1, highlightInfo) desc = string.gsub(desc, objective, "|c"..unitColor..objective.."|r") Questie_TooltipCache[cacheKey]['lines'][lineIndex] = { ['color'] = {1,1,1}, ['data'] = desc, ['wrap'] = false } lineIndex = lineIndex + 1 for i, line in pairs(lines) do Questie_TooltipCache[cacheKey]['lines'][lineIndex] = { ['color'] = {1,1,1}, ['data'] = line } lineIndex = lineIndex + 1 end Questie_TooltipCache[cacheKey]['lineCount'] = lineIndex end end end end QSelect_QuestLogEntry(prevQuestLogSelection) end for k, v in pairs(Questie_TooltipCache[cacheKey]['lines']) do if (not __TT_LineCache[k]) or (not __TT_LineCache[k][v['data']]) then local wrap = v['wrap'] if wrap == nil then wrap = true end GameTooltip:AddLine(v['data'], v['color'][1], v['color'][2], v['color'][3], wrap, k) end end if(QUESTIE_DEBUG_TOOLTIP) then GameTooltip:AddLine("--Questie hook--") end if(forceShow) then GameTooltip:Show() end GameTooltip.QuestieDone = true Questie_LastTooltip = GetTime() --Questie_TooltipCache = {} mi = nil end --------------------------------------------------------------------------------------------------- -- Tooltip code for quest starters and finishers --------------------------------------------------------------------------------------------------- function Questie:GetTooltipLines(path, indent, highlightInfo, lines) if lines == nil then lines = {} end local indentString = ""; for i=1,indent,1 do indentString = indentString.." "; end if path["contained_id"] then path["contained"] = nil; end for sourceType, sources in pairs(path) do local prefix; if sourceType == "drop" then prefix = "Dropped by"; elseif sourceType == "rewardedby" then prefix = "Awarded by"; elseif sourceType == "contained" then prefix = "Contained in"; elseif sourceType == "contained_id" then prefix = "Contained in"; elseif sourceType == "containedi" then prefix = "Opened in"; elseif sourceType == "created" then prefix = "Created by"; elseif sourceType == "openedby" then prefix = "Opened by"; elseif sourceType == "transforms" then prefix = "Used on"; elseif sourceType == "transformedby" then prefix = "Created by"; end if prefix then for sourceName, sourcePath in pairs(sources) do local splitNames = Questie:SplitString(sourceName, ", "); local combinedNames = ""; local countDown = table.getn(splitNames); for i, name in pairs(splitNames) do if i <= 5 or (highlightInfo ~= nil and name == highlightInfo.text) then if i > 1 then combinedNames = combinedNames..", "; end if highlightInfo ~= nil and name == highlightInfo.text then combinedNames = combinedNames.."|r|c"..highlightInfo.color..name.."|r|cFFa6a6a6"; else combinedNames = combinedNames..name; end countDown = countDown - 1; end end if countDown > 0 then combinedNames = combinedNames.." and "..countDown.." more..."; end table.insert(lines, indentString..prefix..": |cFFa6a6a6"..combinedNames.."|r"); Questie:GetTooltipLines(sourcePath, indent+1, highlightInfo, lines, sourceNames); end end end return lines end --------------------------------------------------------------------------------------------------- function Questie:AddPathToTooltip(Tooltip, path, indent) local lines = Questie:GetTooltipLines(path, indent); for i, line in pairs(lines) do Tooltip:AddLine(line,1,1,1,true); end end --------------------------------------------------------------------------------------------------- function Questie_Tooltip_OnEnter() if(this.data.questHash) then local Tooltip = GameTooltip; if(this.type == "WorldMapNote") then Tooltip = WorldMapTooltip; else Tooltip = GameTooltip; end Tooltip:SetOwner(this, this); Tooltip.owner = this local count = 0; local canManualComplete = 0; local orderedQuests = {}; for questHash, questMeta in pairs(this.quests) do orderedQuests[questMeta['sortOrder']] = questMeta; end local prevQuestLogSelection = QGet_QuestLogSelection(); for i, questMeta in pairs(orderedQuests) do local data = questMeta['quest']; count = count + 1; if (count > 1) then Tooltip:AddLine(" "); end if(data.icontype ~= "available" and data.icontype ~= "availablesoon") then local Quest = Questie:IsQuestFinished(data.questHash); if not Quest then local QuestLogID = Questie:GetQuestIdFromHash(data.questHash); if QuestLogID then QSelect_QuestLogEntry(QuestLogID); local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(QuestLogID); Tooltip:AddLine(q); for objectiveid, objectivePath in pairs(questMeta['objectives']) do local objectiveName; if type(objectiveid) == "string" then objectiveName = objectiveid; else local desc, typ, done = QGet_QuestLogLeaderBoard(objectiveid); objectiveName = desc; end Tooltip:AddLine(objectiveName,1,1,1); Questie:AddPathToTooltip(Tooltip, objectivePath, 1); end end else Tooltip:AddLine("["..QuestieHashMap[data.questHash].questLevel.."] "..Quest["name"].." |cFF33FF00(complete)|r"); Tooltip:AddLine("Finished by: |cFFa6a6a6"..QuestieHashMap[data.questHash].finishedBy.."|r",1,1,1); end else questOb = nil; local QuestName = tostring(QuestieHashMap[data.questHash].name); if QuestName then local index = 0; for k,v in pairs(Questie:SanitisedQuestLookup(QuestName)) do index = index + 1; if (index == 1) and (v[2] == data.questHash) and (k ~= "") then questOb = k; elseif (index > 0) and(v[2] == data.questHash) and (k ~= "") then questOb = k; elseif (index == 1) and (v[2] ~= data.questHash) and (k ~= "") then questOb = k; end end end local questLine = "["..QuestieHashMap[data.questHash].questLevel.."] "..QuestieHashMap[data.questHash].name; if data.icontype == "available" then questLine = questLine.." |cFF33FF00(available)|r"; elseif data.icontype == "availablesoon" then questLine = questLine.." |cFFa6a6a6(not available)|r"; end Tooltip:AddLine(questLine); Tooltip:AddLine("Min Level: |cFFa6a6a6"..QuestieHashMap[data.questHash].level.."|r",1,1,1); Tooltip:AddLine("Started by: |cFFa6a6a6"..Questie:RemoveUniqueSuffix(QuestieHashMap[data.questHash].startedBy).."|r",1,1,1); Questie:AddPathToTooltip(Tooltip, questMeta['path'], 1); if questOb ~= nil then Tooltip:AddLine("Description: |cFFa6a6a6"..Questie:RemoveUniqueSuffix(questOb).."|r",1,1,1,true); end canManualComplete = 1; end end QSelect_QuestLogEntry(prevQuestLogSelection); if canManualComplete > 0 then if count > 1 then Tooltip:AddLine(" "); end Tooltip:AddLine("Shift+Click: |cFFa6a6a6Manually complete quest!|r",1,1,1); end if(NOTES_DEBUG and IsAltKeyDown()) then Tooltip:AddLine("!DEBUG!", 1, 0, 0); Tooltip:AddLine("QuestID: "..this.data.questHash, 1, 0, 0); end Tooltip:SetFrameStrata("TOOLTIP"); Tooltip:Show(); end end --------------------------------------------------------------------------------------------------- -- Force a quest to be finished via the Minimap or Worldmap (Shift-Click icon - NO confirmation) --------------------------------------------------------------------------------------------------- function Questie_AvailableQuestClick() if this.type == "WorldMapNote" then local c, z = GetCurrentMapContinent(), GetCurrentMapZone(); local newC, newZ = c, z; if arg1 == "LeftButton" then if c == 0 then newC = this.data.continent; else newZ = this.data.zoneid; end end if arg1 == "RightButton" or arg1 == "MiddleButton" then if z == 0 then newC = 0; else newZ = 0; end end if newC ~= c or newZ ~= z then SetMapZoom(newC, newZ); return; end end local Tooltip = GameTooltip; if(this.type == "WorldMapNote") then Tooltip = WorldMapTooltip; else Tooltip = GameTooltip; end if (QuestieConfig.arrowEnabled == true) and (arg1 == "LeftButton") and (not IsControlKeyDown()) and (not IsShiftKeyDown()) then SetArrowFromIcon(this); end if ((this.data.icontype == "available" or this.data.icontype == "availablesoon" or this.data.icontype == "complete") and IsShiftKeyDown() and Tooltip ) then local finishQuest = function(quest) if (quest.icontype == "available" or quest.icontype == "availablesoon") then local hash = quest.questHash; local questName = "["..QuestieHashMap[hash].questLevel.."] "..QuestieHashMap[hash]['name']; Questie:finishAndRecurse(hash); DEFAULT_CHAT_FRAME:AddMessage("Completing quest |cFF00FF00\"" .. questName .. "\"|r ("..hash..") and parent quests."); --Questie:debug_Print("Notes:Questie_AvailableQuestClick --> Refreshing QuestNPC Icons: [AddEvent:DRAWNOTES]"); Questie:AddEvent("DRAWNOTES", 0.1); end end local count = 0; local firstQuest; for questHash, questMeta in pairs(this.quests) do count = count + 1; if not firstQuest then firstQuest = questMeta['quest']; end end if (count < 2) then -- Finish first quest in list finishQuest(firstQuest); else -- Open Dewdrop to select which quest to finish local closeFunc = function() Dewdrop:Close(); end local registerDewdrop = function(frame, quests, k1, v1, k2, v2) Dewdrop:Register(frame, 'children', function() for questHash, questMeta in pairs(quests) do local quest = questMeta.quest; local hash = questHash; local questName = "["..QuestieHashMap[hash].questLevel.."] "..QuestieHashMap[hash]['name'] local finishFunc = function(quest) finishQuest(quest); Dewdrop:Close(); end Dewdrop:AddLine( 'text', questName, 'notClickable', quest.icontype ~= "available" and quest.icontype ~= "availablesoon", 'icon', QuestieIcons[quest.icontype].path, 'iconCoordLeft', 0, 'iconCoordRight', 1, 'iconCoordTop', 0, 'iconCoordBottom', 1, 'func', finishFunc, 'arg1', quest ); end Dewdrop:AddLine( 'text', "", 'notClickable', true ); Dewdrop:AddLine( 'text', "Cancel", 'func', closeFunc ); end, 'dontHook', true, k1, v1, k2, v2 ); Dewdrop:Open(frame); Dewdrop:Unregister(frame); end if (IsAddOnLoaded("Cartographer")) or (IsAddOnLoaded("MetaMap")) or (QuestieConfig.resizeWorldmap == true) then registerDewdrop(WorldMapFrame, this.quests, 'cursorX', true, 'cursorY', true); elseif (not IsAddOnLoaded("Cartographer")) or (not IsAddOnLoaded("MetaMap")) and (QuestieConfig.resizeWorldmap == false) then registerDewdrop(this, this.quests, 'point', "TOPLEFT", 'relativePoint', "BOTTOMRIGHT"); elseif (IsAddOnLoaded("Cartographer")) and (CartographerDB["disabledModules"]["Default"]["Look 'n' Feel"] == true) then registerDewdrop(this, this.quests, 'point', "TOPLEFT", 'relativePoint', "BOTTOMRIGHT"); end end end end --------------------------------------------------------------------------------------------------- -- Creates a blank frame for use within the map system --------------------------------------------------------------------------------------------------- function Questie:CreateBlankFrameNote(frame) local f = CreateFrame("Button","QuestieNoteFrame"..CREATED_NOTE_FRAMES,frame); local t = f:CreateTexture(nil,"BACKGROUND"); f.texture = t; f:SetScript("OnEnter", Questie_Tooltip_OnEnter); f:SetScript("OnLeave", function() if(WorldMapTooltip) then WorldMapTooltip:Hide(); end if(GameTooltip) then GameTooltip:Hide(); GameTooltip.owner = nil end end) f:SetScript("OnClick", Questie_AvailableQuestClick); f:RegisterForClicks("LeftButtonDown", "RightButtonDown", "MiddleButtonDown"); CREATED_NOTE_FRAMES = CREATED_NOTE_FRAMES+1; table.insert(FramePool, f); table.insert(AllFrames, f); end --------------------------------------------------------------------------------------------------- function Questie:GetFrameNote(data, parentFrame, frameLevel, type, scale) if(table.getn(FramePool)==0) then Questie:CreateFrameNote(data, parentFrame, frameLevel, type, scale); end f = FramePool[1]; table.remove(FramePool, 1); return f; end --------------------------------------------------------------------------------------------------- function Questie:SetFrameNoteData(f, data, parentFrame, frameLevel, type, scale) f.data = data; f.quests = {}; Questie:AddFrameNoteData(f, data); f:SetParent(parentFrame); f:SetFrameLevel(frameLevel); f:SetPoint("CENTER",0,0); f.type = type; f:SetWidth(16*scale); f:SetHeight(16*scale); f.texture:SetTexture(QuestieIcons[data.icontype].path); f.texture:SetAllPoints(f); end --------------------------------------------------------------------------------------------------- function Questie:AddFrameNoteData(icon, data) if icon then if (icon.averageX == nil or icon.averageY == nil or icon.countForAverage == nil) then icon.averageX = 0; icon.averageY = 0; icon.countForAverage = 0; end local numQuests = 0; for k, v in pairs(icon.quests) do numQuests = numQuests + 1; end local newAverageX = (icon.averageX * icon.countForAverage + data.x) / (icon.countForAverage + 1); local newAverageY = (icon.averageY * icon.countForAverage + data.y) / (icon.countForAverage + 1); icon.averageX = newAverageX; icon.averageY = newAverageY; icon.countForAverage = icon.countForAverage + 1; if icon.quests[data.questHash] then -- Add cumulative quest data if icon.quests[data.questHash]['objectives'][data.objectiveid] == nil then icon.quests[data.questHash]['objectives'][data.objectiveid] = {}; end if data.path then Questie:JoinPathTables(icon.quests[data.questHash]['path'], data.path); end if data.objectiveid and data.path then Questie:JoinPathTables(icon.quests[data.questHash]['objectives'][data.objectiveid], data.path); end else icon.quests[data.questHash] = {}; icon.quests[data.questHash]['quest'] = data; icon.quests[data.questHash]['sortOrder'] = numQuests + 1; icon.quests[data.questHash]['objectives'] = {}; icon.quests[data.questHash]['path'] = {}; if data.objectiveid then icon.quests[data.questHash]['objectives'][data.objectiveid] = {}; if data.path then icon.quests[data.questHash]['objectives'][data.objectiveid] = deepcopy(data.path); end end if data.path then icon.quests[data.questHash]['path'] = deepcopy(data.path); end end end end --------------------------------------------------------------------------------------------------- function Questie:JoinPathTables(path1, path2) for k, v in pairs(path2) do if path1[k] then --Questie:debug_Print("Joining values for "..k) Questie:JoinPathTables(path1[k], path2[k]); else --Questie:debug_Print("Setting value for "..k) path1[k] = path2[k]; end end end --------------------------------------------------------------------------------------------------- function Questie:PathsAreIdentical(path1, path2) if not next(path1) and not next(path2) then return true; end for sourceType1, sources1 in pairs(path1) do for sourceType2, sources2 in pairs(path2) do if path1[sourceType2] == nil or path2[sourceType1] == nil then return false; end end for sourceName, sourcePath in pairs(path1[sourceType1]) do for otherSourceName, otherSourcePath in pairs(path2[sourceType1]) do if path1[sourceType1][otherSourceName] == nil or path2[sourceType1][sourceName] == nil then return false; end end end end return true; end --------------------------------------------------------------------------------------------------- function Questie:PostProcessIconPath(path) if path["locations"] then path["locations"] = nil; end if path["name"] then path["name"] = nil; end for sourceType, sources in pairs(path) do for sourceName, sourcePath in pairs(sources) do Questie:PostProcessIconPath(sourcePath); end local newSources = {}; for sourceName, sourcePath in pairs(sources) do for otherSourceName, otherSourcePath in pairs(sources) do if sourceName ~= otherSourceName and (newSources[sourceName] == nil or newSources[otherSourceName] == nil) then if Questie:PathsAreIdentical(sourcePath, otherSourcePath) then local newSource = newSources[sourceName]; if newSource == nil then newSource = newSources[otherSourceName]; end if newSource ~= nil then newSource.name = newSource.name..", "..otherSourceName; table.insert(newSource.names, otherSourceName); else newSource = { ['name'] = sourceName..", "..otherSourceName, ['names'] = {sourceName, otherSourceName}, ['sourcePath'] = sourcePath }; end for i, name in ipairs(newSource.names) do newSources[name] = newSource; end end end end end for sourceName, sourcePath in pairs(sources) do if newSources[sourceName] == nil then newSources[sourceName] = { ['name'] = sourceName, ['sourcePath'] = sourcePath, ['names'] = {sourceName} }; end end local processedSources = {}; for sourceName, data in pairs(newSources) do processedSources[data.name] = data.sourcePath; end path[sourceType] = processedSources; end end --------------------------------------------------------------------------------------------------- function Questie:RecursiveGetSourceNamesFromRawPath(path, sourceNames) if sourceNames == nil then sourceNames = {} end for sourceType, sources in pairs(path) do if sourceType ~= "locations" and sourceType ~= "name" then for sourceName, sourcePath in pairs(sources) do sourceNames[sourceName] = true Questie:RecursiveGetSourceNamesFromRawPath(sourcePath, sourceNames) end end end return sourceNames end --------------------------------------------------------------------------------------------------- function Questie:RecursiveFindAndCombineObjectiveName(pathToSearch, objectiveName, pathToAdd) local found = false; for sourceType, sources in pairs(pathToSearch) do for sourceName, sourcePath in pairs(sources) do if sourceName == objectiveName then sources[sourceName] = pathToAdd; found = true; else if Questie:RecursiveFindAndCombineObjectiveName(sourcePath, objectiveName, pathToAdd) then found = true; end end end end return found; end --------------------------------------------------------------------------------------------------- function Questie:FindAndCombineObjectiveName(objectives, objectiveName, pathToAdd) for objectiveid, objectivePath in pairs(objectives) do if type(objectiveid) ~= "string" then if Questie:RecursiveFindAndCombineObjectiveName(objectivePath, objectiveName, pathToAdd) then objectives[objectiveName] = nil; end end end end --------------------------------------------------------------------------------------------------- function Questie:PostProcessIconPaths(icon) for questHash, questMeta in pairs(icon.quests) do Questie:PostProcessIconPath(questMeta.path); for objectiveid, objectivePath in pairs(questMeta.objectives) do if type(objectiveid) == "string" then Questie:FindAndCombineObjectiveName(questMeta.objectives, objectiveid, objectivePath); end Questie:PostProcessIconPath(objectivePath); end end end --------------------------------------------------------------------------------------------------- -- Updates notes for current zone only --------------------------------------------------------------------------------------------------- function Questie:NOTES_ON_UPDATE(elapsed) if GameLoadingComplete == false then return; end local c, z = GetCurrentMapContinent(), GetCurrentMapZone(); if(c ~= LastContinent or LastZone ~= z) then --Questie:debug_Print("Notes:NOTES_ON_UPDATE: [AddEvent:DRAWNOTES]"); Questie:SetAvailableQuests(); Questie:RedrawNotes(); LastContinent = c; LastZone = z; end if(WorldMapFrame:IsVisible() and UIOpen == false) then --Questie:debug_Print("NOTES_ON_UPDATE: Created Frames: "..CREATED_NOTE_FRAMES, "Used Frames: "..table.getn(QuestieUsedNoteFrames), "Free Frames: "..table.getn(FramePool)); UIOpen = true; elseif(WorldMapFrame:IsVisible() == nil and UIOpen == true) then UIOpen = false; end end --------------------------------------------------------------------------------------------------- -- Inital pool size (Not tested how much you can do before it lags like shit, from experiance 11 -- is good) --------------------------------------------------------------------------------------------------- function Questie:NOTES_LOADED() --Questie:debug_Print("NOTES_LOADED: Loading QuestieNotes"); if(table.getn(FramePool) < 10) then for i = 1, INIT_POOL_SIZE do Questie:CreateBlankFrameNote(); end end --Questie:debug_Print("NOTES_LOADED: Done Loading QuestieNotes"); end --------------------------------------------------------------------------------------------------- function Questie:RecursiveGetPathLocations(path, locations) if locations == nil then locations = {}; end for sourceType, sources in pairs(path) do if sourceType == "locations" and next(sources) then for i, location in pairs(sources) do table.insert(locations, location); end elseif sourceType == "drop" or sourceType == "rewardedby" or sourceType == "contained" or sourceType == "contained_id" or sourceType == "created" or sourceType == "containedi" or sourceType == "transforms" or sourceType == "transformedby" then for sourceName, sourcePath in pairs(sources) do Questie:RecursiveGetPathLocations(sourcePath, locations); end end end return locations; end --------------------------------------------------------------------------------------------------- function Questie:RecursiveCreateNotes(c, z, v, locationMeta, iconMeta, objectiveid, path, pathKeys) if path == nil then path = {}; end if pathKeys == nil then pathKeys = {}; end for sourceType, sources in pairs(locationMeta) do if sourceType == "locations" and next(sources) then for specialSource, b in pairs(specialSources) do if locationMeta[specialSource] ~= nil and next(locationMeta[specialSource]) then local pathToAppend = path; for i, pathKey in pairs(pathKeys) do pathToAppend = pathToAppend[pathKey]; end pathToAppend[specialSource] = {}; for sourceName, sourcePath in pairs(locationMeta[specialSource]) do pathToAppend[specialSource][sourceName] = {}; end end end for i, location in pairs(sources) do local MapInfo = QuestieZoneIDLookup[location[1]]; if MapInfo ~= nil then c = MapInfo[4]; z = MapInfo[5]; local icontype = iconMeta.selectedIcon; if icontype == nil then icontype = iconMeta.defaultIcon; end if icontype == "available" or icontype == "availablesoon" then Questie:AddAvailableNoteToMap(location[1],location[2],location[3],location[4],icontype,v,-1,deepcopy(path)); else Questie:AddNoteToMap(location[1],location[2],location[3],location[4],icontype,v,objectiveid,deepcopy(path)); end end end elseif sourceType == "drop" or sourceType == "rewardedby" or sourceType == "contained" or sourceType == "contained_id" or sourceType == "created" or sourceType == "containedi" or sourceType == "openedby" or sourceType == "transforms" or sourceType == "transformedby" then for sourceName, sourceLocationMeta in pairs(sources) do local newPath = deepcopy(path); local editPath = newPath; for i, pathKey in pairs(pathKeys) do editPath = editPath[pathKey]; end editPath[sourceType] = {}; editPath[sourceType][sourceName] = {}; local newPathKeys = deepcopy(pathKeys); table.insert(newPathKeys, sourceType); table.insert(newPathKeys, sourceName); local newIconMeta = deepcopy(iconMeta); if newIconMeta.selectedIcon == nil then local typeToIcon = { ["drop"] = "loot", ["rewardedby"] = "slay", ["contained"] = "object", ["contained_id"] = "object", ["created"] = "event", ["containedi"] = "object", ["openedby"] = "object", ["transforms"] = "event", ["transformedby"] = "loot", }; newIconMeta.selectedIcon = typeToIcon[sourceType]; end local newObjectiveId = objectiveid; if specialSources[sourceType] then newPath = {}; newPathKeys = {}; newObjectiveId = sourceName; newIconMeta.selectedIcon = nil; end Questie:RecursiveCreateNotes(c, z, v, sourceLocationMeta, newIconMeta, newObjectiveId, newPath, newPathKeys); end end end end --------------------------------------------------------------------------------------------------- -- Sets up all available quests --------------------------------------------------------------------------------------------------- function Questie:SetAvailableQuests(customLevel) QuestieAvailableMapNotes = {}; local saqtime = GetTime(); local level = customLevel or UnitLevel("player"); local c, z = GetCurrentMapContinent(), GetCurrentMapZone(); local mapFileName = GetMapInfo(); local quests = nil; local minLevel = 0; local maxLevel = 100; if QuestieConfig.minLevelFilter then minLevel = level - QuestieConfig.minShowLevel; end if QuestieConfig.maxLevelFilter then maxLevel = level + QuestieConfig.maxShowLevel; end quests = Questie:GetAvailableQuestHashes(mapFileName, minLevel, maxLevel); if quests then local count = 0; for k, v in pairs(quests) do count = count + 1; local icontype = "available"; if QuestieHashMap[k].level > level then icontype = "availablesoon"; end Questie:RecursiveCreateNotes(c, z, k, v, {["selectedIcon"] = icontype}); end --Questie:debug_Print("SetAvailableQuests: Adding "..count.." available quests took "..tostring((GetTime()- saqtime)*1000).."ms"); saqtime = nil; end end --------------------------------------------------------------------------------------------------- -- Reason this exists is to be able to call both clearnotes and drawnotes without doing 2 function -- calls, and to be able to force a redraw --------------------------------------------------------------------------------------------------- function Questie:RedrawNotes() Questie:CLEAR_ALL_NOTES(); Questie:DRAW_NOTES(); end --------------------------------------------------------------------------------------------------- function Questie:Clear_Note(v) v:SetParent(nil); v:Hide(); v:SetAlpha(1); v:SetFrameLevel(9); v:SetHighlightTexture(nil, "ADD"); v.questHash = nil; v.objId = nil; v.data = nil; v.quests = nil; v.averageX = nil; v.averageY = nil; v.countForAverage = nil; table.insert(FramePool, v); end --------------------------------------------------------------------------------------------------- -- Clears the notes, goes through the usednoteframes and clears them. Then sets the -- QuestieUsedNotesFrame to new table; --------------------------------------------------------------------------------------------------- function Questie:CLEAR_ALL_NOTES() --Questie:debug_Print("CLEAR_ALL_NOTES"); Astrolabe:RemoveAllMinimapIcons(); clustersByFrame = nil; for k, v in pairs(QuestieUsedNoteFrames) do Questie:Clear_Note(v); end QuestieUsedNoteFrames = {}; end --------------------------------------------------------------------------------------------------- -- Logic for clusters --------------------------------------------------------------------------------------------------- function Cluster.new(points) local self = setmetatable({}, Cluster); self.points = points; return self; end --------------------------------------------------------------------------------------------------- function Cluster:CountPoints() local count = 0; local counted = {}; for i, q in pairs(self.points) do if not counted[q.questHash] then count = count + 1; counted[q.questHash] = true; end end return count; end --------------------------------------------------------------------------------------------------- function Cluster.CalculateDistance(x1, y1, x2, y2) local deltaX = x1 - x2; local deltaY = y1 - y2; return sqrt(deltaX*deltaX + deltaY*deltaY); end --------------------------------------------------------------------------------------------------- function Cluster.CalculateLinkageDistance(cluster1, cluster2) local total = 0; for i, pi in cluster1 do for j, pj in cluster2 do if pi.zoneid ~= pj.zoneid then return -1; end local distance = Cluster.CalculateDistance(pi.x, pi.y, pj.x, pj.y); total = total + distance; end end return total / (table.getn(cluster1) * table.getn(cluster2)); end --------------------------------------------------------------------------------------------------- function Cluster:CalculateClusters(clusters, distanceThreshold, maxClusterSize) while table.getn(clusters) > 1 do local nearest1; local nearest2; local nearestDistance; for i, cluster in pairs(clusters) do for j, otherCluster in pairs(clusters) do if cluster ~= otherCluster then local distance = Cluster.CalculateLinkageDistance(cluster.points, otherCluster.points); if distance >= 0 and (distance == 0 or ((nearestDistance == nil or distance < nearestDistance) and (cluster:CountPoints() + otherCluster:CountPoints() <= maxClusterSize))) then nearestDistance = distance; nearest1 = cluster; nearest2 = otherCluster; end end if nearestDistance == 0 then break; end end if nearestDistance == 0 then break; end end if nearestDistance == nil or nearestDistance > distanceThreshold then break; end local index1 = indexOf(clusters, nearest1); table.remove(clusters, index1); local index2 = indexOf(clusters, nearest2); table.remove(clusters, index2); local points = nearest1.points; for i, point in pairs(nearest2.points) do table.insert(points, point); end local newCluster = Cluster.new(points); table.insert(clusters, newCluster); end end --------------------------------------------------------------------------------------------------- -- splits the specified text into an array on the specified separator -- todo make a QuestieUtils.lua file for things like this --------------------------------------------------------------------------------------------------- function Questie:SplitString( text, separator, limit ) local parts, position, length, last, jump, count = {}, 1, string.len( text ), nil, string.len( separator ), 0; while true do last = string.find( text, separator, position, true ); if last and ( not limit or count < limit ) then table.insert( parts, string.sub( text, position, last - 1 ) ); position, count = last + jump, count + 1; else table.insert( parts, string.sub( text, position ) ); break; end end return parts; end --------------------------------------------------------------------------------------------------- function Questie:RoundCoordinate(coord, factor) if factor == nil then factor = 1; end return tonumber(string.format("%.2f", coord/factor)) * factor; end --------------------------------------------------------------------------------------------------- function Questie:GetReactionColor(reaction) if reaction == nil or reaction < 1 or reaction > 8 then reaction = 4; end return FACTION_BAR_COLORS[reaction]; end --------------------------------------------------------------------------------------------------- function Questie:AddClusterFromNote(frame, identifier, v) if clustersByFrame == nil then clustersByFrame = {}; end if clustersByFrame[frame] == nil then clustersByFrame[frame] = {}; end if clustersByFrame[frame][identifier] == nil then clustersByFrame[frame][identifier] = {}; end if clustersByFrame[frame][identifier][v.continent] == nil then clustersByFrame[frame][identifier][v.continent] = {}; end if clustersByFrame[frame][identifier][v.continent][v.zoneid] == nil then clustersByFrame[frame][identifier][v.continent][v.zoneid] = {}; end local roundedX = v.x; local roundedY = v.y; if QuestieConfig.clusterQuests and frame == "WorldMapNote" and identifier == "Objectives" then roundedX = Questie:RoundCoordinate(v.x, 5); roundedY = Questie:RoundCoordinate(v.y, 5); end if clustersByFrame[frame][identifier][v.continent][v.zoneid][roundedX] == nil then clustersByFrame[frame][identifier][v.continent][v.zoneid][roundedX] = {}; end if clustersByFrame[frame][identifier][v.continent][v.zoneid][roundedX][roundedY] == nil then local points = { v }; local cluster = Cluster.new(points); clustersByFrame[frame][identifier][v.continent][v.zoneid][roundedX][roundedY] = cluster; else table.insert(clustersByFrame[frame][identifier][v.continent][v.zoneid][roundedX][roundedY].points, v); end end --------------------------------------------------------------------------------------------------- function Questie:GetClustersByFrame(frame, identifier) if clustersByFrame == nil then clustersByFrame = {}; end if clustersByFrame[frame] == nil then clustersByFrame[frame] = {}; end if clustersByFrame[frame][identifier] == nil then clustersByFrame[frame][identifier] = {}; end local clusters = {}; for c, v in pairs(clustersByFrame[frame][identifier]) do for z, v in pairs(clustersByFrame[frame][identifier][c]) do for x, v in pairs(clustersByFrame[frame][identifier][c][z]) do for y, v in pairs(clustersByFrame[frame][identifier][c][z][x]) do table.insert(clusters, clustersByFrame[frame][identifier][c][z][x][y]); end end end end return clusters; end --------------------------------------------------------------------------------------------------- -- Finds the index of an item in a table. Not sure if a function already exists somewhere. --------------------------------------------------------------------------------------------------- function indexOf(table, item) for k, v in pairs(table) do if v == item then return k; end end return nil; end --------------------------------------------------------------------------------------------------- -- Checks first if there are any notes for the current zone, then draws the desired icon --------------------------------------------------------------------------------------------------- function Questie:DRAW_NOTES() --Questie:debug_Print("DRAW_NOTES"); local c, z = GetCurrentMapContinent(), GetCurrentMapZone(); if (not QuestieConfig.hideMinimapIcons) then -- Draw minimap objective markers if (QuestieMapNotes[c] and QuestieMapNotes[c][z]) then for k, v in pairs(QuestieMapNotes[c][z]) do --If an available quest isn't in the zone or we aren't tracking a quest on the QuestTracker or the user wants to hide all objectives then hide the objectives from the minimap local show = QuestieConfig.alwaysShowObjectives or ((MMLastX ~= 0) and (MMLastY ~= 0)) and (QuestieCachedQuests[v.questHash] ~= nil) and (QuestieCachedQuests[v.questHash]["tracked"] ~= false); if show then if (v.icontype == "complete") then Questie:AddClusterFromNote("MiniMapNote", "Quests", v); else if QuestieConfig.hideObjectives == false then Questie:AddClusterFromNote("MiniMapNote", "Objectives", v); end end end end end end -- Draw world map objective markers for k, Continent in pairs(QuestieMapNotes) do for zone, noteHeap in pairs(Continent) do for k, v in pairs(noteHeap) do if true then --If we aren't tracking a quest on the QuestTracker or the user wants to hide all objectives then hide the objectives from the worldmap if (((QuestieCachedQuests[v.questHash] ~= nil) and (QuestieCachedQuests[v.questHash]["tracked"] ~= false)) or (v.icontype == "complete")) and (QuestieConfig.alwaysShowObjectives == false) then if (v.icontype == "complete") then Questie:AddClusterFromNote("WorldMapNote", "Quests", v); else if QuestieConfig.hideObjectives == false then Questie:AddClusterFromNote("WorldMapNote", "Objectives", v); end end elseif (QuestieConfig.alwaysShowObjectives == true) then if (v.icontype == "complete") then Questie:AddClusterFromNote("WorldMapNote", "Quests", v); else if QuestieConfig.hideObjectives == false then Questie:AddClusterFromNote("WorldMapNote", "Objectives", v); end end end end end end end -- Draw available quest markers. if (QuestieAvailableMapNotes[c] and QuestieAvailableMapNotes[c][z]) then if (IsQuestieActive == true) then local con,zon,x,y = Astrolabe:GetCurrentPlayerPosition(); for k, v in pairs(QuestieAvailableMapNotes[c][z]) do Questie:AddClusterFromNote("WorldMapNote", "Quests", v); if (not QuestieConfig.hideMinimapIcons) then Questie:AddClusterFromNote("MiniMapNote", "Quests", v); end end end end local minimapObjectiveClusters = Questie:GetClustersByFrame("MiniMapNote", "Objectives"); local worldMapObjectiveClusters = Questie:GetClustersByFrame("WorldMapNote", "Objectives"); local minimapClusters = Questie:GetClustersByFrame("MiniMapNote", "Quests"); local worldMapClusters = Questie:GetClustersByFrame("WorldMapNote", "Quests"); if QuestieConfig.clusterQuests then Cluster:CalculateClusters(worldMapClusters, 0.025, 5); end local scale = QUESTIE_NOTES_MAP_ICON_SCALE; if (z == 0 and c == 0) then--Both continents scale = QUESTIE_NOTES_WORLD_MAP_ICON_SCALE; elseif (z == 0) then--Single continent scale = QUESTIE_NOTES_CONTINENT_ICON_SCALE; end Questie:DrawClusters(worldMapObjectiveClusters, "WorldMapNote", scale, WorldMapFrame, WorldMapButton); Questie:DrawClusters(worldMapClusters, "WorldMapNote", scale, WorldMapFrame, WorldMapButton); Questie:DrawClusters(minimapObjectiveClusters, "MiniMapNote", QUESTIE_NOTES_MINIMAP_ICON_SCALE, Minimap); Questie:DrawClusters(minimapClusters, "MiniMapNote", QUESTIE_NOTES_MINIMAP_ICON_SCALE, Minimap); end --------------------------------------------------------------------------------------------------- function Questie:DrawClusters(clusters, frameName, scale, frame, button) local frameLevel = 9; if frameName == "MiniMapNote" then frameLevel = 7; end for i, cluster in pairs(clusters) do table.sort(cluster.points, function(a, b) if QuestieIcons[a.icontype].priority ~= QuestieIcons[b.icontype].priority then return QuestieIcons[a.icontype].priority < QuestieIcons[b.icontype].priority end if a.questHash == b.questHash then return tostring(a) < tostring(b) end local questA = QuestieHashMap[a.questHash] local questB = QuestieHashMap[b.questHash] if not questA or not questB then return questA ~= nil end if questA and questB then if questA.level ~= questB.level then return questA.level < questB.level end local questLevelA = GetNumberFromString(questA.questLevel) local questLevelB = GetNumberFromString(questB.questLevel) if questLevelA ~= questLevelB then return questLevelA < questLevelB end end return a.questHash < b.questHash end) local Icon = Questie:GetBlankNoteFrame(frame); for j, v in pairs(cluster.points) do if j == 1 then local finalFrameLevel = frameLevel; if v.icontype == "complete" then finalFrameLevel = finalFrameLevel + 1; end Questie:SetFrameNoteData(Icon, v, frame, finalFrameLevel, frameName, scale); else Questie:AddFrameNoteData(Icon, v); end end Questie:PostProcessIconPaths(Icon); if frameName == "MiniMapNote" then Icon:SetHighlightTexture(QuestieIcons[Icon.data.icontype].path, "ADD"); Astrolabe:PlaceIconOnMinimap(Icon, Icon.data.continent, Icon.data.zoneid, Icon.averageX, Icon.averageY); table.insert(QuestieUsedNoteFrames, Icon); else Icon:Show(); xx, yy = Astrolabe:PlaceIconOnWorldMap(button, Icon, Icon.data.continent, Icon.data.zoneid, Icon.averageX, Icon.averageY); if(xx and yy and xx > 0 and xx < 1 and yy > 0 and yy < 1) then table.insert(QuestieUsedNoteFrames, Icon); else Questie:Clear_Note(Icon); end end end end --------------------------------------------------------------------------------------------------- -- Debug print function --------------------------------------------------------------------------------------------------- function Questie:debug_Print(...) local debugWin = 0; local name, shown; for i=1, NUM_CHAT_WINDOWS do name,_,_,_,_,_,shown = GetChatWindowInfo(i); if (string.lower(name) == "questiedebug") then debugWin = i; break; end end if (debugWin == 0) then return; end local out = ""; for i = 1, arg.n, 1 do if (i > 1) then out = out .. ", "; end local t = type(arg[i]); if (t == "string") then out = out .. '"'..arg[i]..'"'; elseif (t == "number") then out = out .. arg[i]; else out = out .. dump(arg[i]); end end getglobal("ChatFrame"..debugWin):AddMessage(out, 1.0, 1.0, 0.3); end --------------------------------------------------------------------------------------------------- -- Sets the icon type --------------------------------------------------------------------------------------------------- QuestieIcons = { ["complete"] = { text = "Complete", path = "Interface\\AddOns\\!Questie\\Icons\\complete", priority = 1 }, ["available"] = { text = "Complete", path = "Interface\\AddOns\\!Questie\\Icons\\available", priority = 2 }, ["availablesoon"] = { text = "Complete", path = "Interface\\AddOns\\!Questie\\Icons\\availablesoon", priority = 2 }, ["loot"] = { text = "Complete", path = "Interface\\AddOns\\!Questie\\Icons\\loot", priority = 3 }, ["item"] = { text = "Complete", path = "Interface\\AddOns\\!Questie\\Icons\\loot", priority = 3 }, ["event"] = { text = "Complete", path = "Interface\\AddOns\\!Questie\\Icons\\event", priority = 3 }, ["object"] = { text = "Complete", path = "Interface\\AddOns\\!Questie\\Icons\\object", priority = 3 }, ["slay"] = { text = "Complete", path = "Interface\\AddOns\\!Questie\\Icons\\slay", priority = 3 } };