v9.7.2: Ebonhold Database integration and core logic refinements
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
---@type QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:CreateModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
|
||||
---@type QuestieDB
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
--- COMPATIBILITY ---
|
||||
local CALENDAR_FULLDATE_MONTH_NAMES = QuestieCompat.CALENDAR_FULLDATE_MONTH_NAMES
|
||||
|
||||
function _QuestieJourney:GetHistory()
|
||||
local journeyEntries = _QuestieJourney:GetJourneyEntries()
|
||||
local years = {}
|
||||
for k in pairs(journeyEntries) do
|
||||
table.insert(years, k)
|
||||
end
|
||||
table.sort(years)
|
||||
|
||||
local history = {}
|
||||
for _, year in pairs(years) do
|
||||
local yearTable = {
|
||||
value = year,
|
||||
text = l10n('Year %s', year),
|
||||
children = {},
|
||||
}
|
||||
|
||||
for month=12, 1, -1 do -- Iterate the month from last to newest
|
||||
if journeyEntries[year][month] then -- Only check month with events
|
||||
local monthView = {
|
||||
value = month,
|
||||
text = CALENDAR_FULLDATE_MONTH_NAMES[month] .. ' '.. year,
|
||||
children = {},
|
||||
}
|
||||
|
||||
for entryIndex=#journeyEntries[year][month], 1, -1 do -- Iterate backwards to show newest first
|
||||
|
||||
---@type JourneyEntry
|
||||
local entry = journeyEntries[year][month][entryIndex]
|
||||
local entryIdx = entry.idx
|
||||
local entryText = _QuestieJourney:GetEntryText(entry.value)
|
||||
|
||||
local entryView = {
|
||||
value = entryIdx,
|
||||
text = entryText,
|
||||
}
|
||||
|
||||
tinsert(monthView.children, entryView)
|
||||
end
|
||||
|
||||
tinsert(yearTable.children, monthView)
|
||||
end
|
||||
end
|
||||
|
||||
tinsert(history, yearTable)
|
||||
end
|
||||
|
||||
return history
|
||||
end
|
||||
|
||||
--- Get a sorted copy of the journey entries.
|
||||
---@return table<string, table<string, SortedJourneyEntry>>
|
||||
function _QuestieJourney:GetJourneyEntries()
|
||||
local dateTable = {}
|
||||
-- -- Sort all of the entries by year and month
|
||||
-- ---@param v JourneyEntry
|
||||
for i, v in ipairs(Questie.db.char.journey) do
|
||||
local year = tonumber(date('%Y', v.Timestamp))
|
||||
if (not dateTable[year]) then
|
||||
dateTable[year] = {}
|
||||
end
|
||||
|
||||
local month = tonumber(date('%m', v.Timestamp))
|
||||
|
||||
if (not dateTable[year][month]) then
|
||||
dateTable[year][month] = {}
|
||||
end
|
||||
|
||||
---@class SortedJourneyEntry
|
||||
local entry = {}
|
||||
---@type number
|
||||
entry.idx = i
|
||||
---@type JourneyEntry
|
||||
entry.value = v
|
||||
|
||||
tinsert(dateTable[year][month], entry)
|
||||
end
|
||||
|
||||
return dateTable
|
||||
end
|
||||
|
||||
function _QuestieJourney:GetEntryText(entry)
|
||||
local entryText = ""
|
||||
|
||||
if entry.Event == "Level" then
|
||||
entryText = l10n('You Reached Level %s', entry.NewLevel)
|
||||
elseif entry.Event == "Note" then
|
||||
entryText = l10n('Note: %s', entry.Title)
|
||||
elseif entry.Event == "Quest" then
|
||||
local state
|
||||
if entry.SubType == "Accept" then
|
||||
state = l10n('Accepted')
|
||||
elseif entry.SubType == "Complete" then
|
||||
state = l10n('Completed')
|
||||
elseif entry.SubType == "Abandon" then
|
||||
state = l10n('Abandoned')
|
||||
else
|
||||
state = "ERROR!!"
|
||||
end
|
||||
local qName = QuestieDB.QueryQuestSingle(entry.Quest, "name")
|
||||
entryText = l10n('Quest %s: %s', state or "no state", qName or "no quest name")
|
||||
end
|
||||
return entryText
|
||||
end
|
||||
@@ -0,0 +1,423 @@
|
||||
---@type QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:CreateModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
-------------------------
|
||||
--Import modules.
|
||||
-------------------------
|
||||
---@type QuestieJourneyUtils
|
||||
local QuestieJourneyUtils = QuestieLoader:ImportModule("QuestieJourneyUtils")
|
||||
---@type QuestieDB
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
||||
---@type QuestieLib
|
||||
local QuestieLib = QuestieLoader:ImportModule("QuestieLib")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
|
||||
|
||||
-- TODO remove again once the call in manageZoneTree was removed
|
||||
---@param container ScrollFrame
|
||||
---@param quest Quest
|
||||
function _QuestieJourney:DrawQuestDetailsFrame(container, quest)
|
||||
local questNameHeader = _QuestieJourney:CreateHeading(quest.name, true)
|
||||
container:AddChild(questNameHeader)
|
||||
|
||||
QuestieJourneyUtils:Spacer(container)
|
||||
|
||||
local obj = AceGUI:Create("Label")
|
||||
obj:SetText(_QuestieJourney:CreateObjectiveText(quest.Description))
|
||||
obj:SetFullWidth(true)
|
||||
container:AddChild(obj)
|
||||
|
||||
QuestieJourneyUtils:Spacer(container)
|
||||
|
||||
local questInfoHeader = _QuestieJourney:CreateHeading(l10n('Quest Information'), true)
|
||||
container:AddChild(questInfoHeader)
|
||||
|
||||
-- Generic Quest Information
|
||||
|
||||
local levelLabel = _QuestieJourney:CreateLabel(Questie:Colorize(l10n('Recommended Quest Level: '), 'yellow') .. quest.level, true)
|
||||
container:AddChild(levelLabel)
|
||||
|
||||
local minLevelLabel = _QuestieJourney:CreateLabel(Questie:Colorize(l10n('Minimum Required Level for Quest: '), 'yellow') .. quest.requiredLevel, true)
|
||||
container:AddChild(minLevelLabel)
|
||||
|
||||
local levelDiffString = _QuestieJourney:GetDifficultyString(quest.level, quest.requiredLevel)
|
||||
local levelDiffLabel = _QuestieJourney:CreateLabel(levelDiffString, true)
|
||||
container:AddChild(levelDiffLabel)
|
||||
|
||||
local questIdLabel = _QuestieJourney:CreateLabel(Questie:Colorize(l10n('Quest ID: '), 'yellow') .. quest.Id, true)
|
||||
container:AddChild(questIdLabel)
|
||||
|
||||
QuestieJourneyUtils:Spacer(container)
|
||||
|
||||
local preQuestCounter, preQuestInlineGroup = _QuestieJourney:CreatePreQuestGroup(quest)
|
||||
if preQuestCounter > 1 then -- Don't add the group if it doesn't contain a pre quest
|
||||
QuestieJourneyUtils:Spacer(preQuestInlineGroup)
|
||||
container:AddChild(preQuestInlineGroup)
|
||||
end
|
||||
|
||||
-- Get Quest Start NPC
|
||||
if quest.Starts and quest.Starts.NPC then
|
||||
local startNPCGroup = AceGUI:Create("InlineGroup")
|
||||
startNPCGroup:SetLayout("List")
|
||||
startNPCGroup:SetTitle(l10n('Quest Start NPC Information'))
|
||||
startNPCGroup:SetFullWidth(true)
|
||||
container:AddChild(startNPCGroup)
|
||||
|
||||
QuestieJourneyUtils:Spacer(startNPCGroup)
|
||||
|
||||
local startNpc = QuestieDB:GetNPC(quest.Starts.NPC[1])
|
||||
|
||||
local startNPCNameLabel = _QuestieJourney:CreateLabel(startNpc.name, true)
|
||||
startNPCNameLabel:SetFontObject(GameFontHighlight)
|
||||
startNPCNameLabel:SetColor(255, 165, 0)
|
||||
startNPCGroup:AddChild(startNPCNameLabel)
|
||||
|
||||
local startNPCZoneLabel = AceGUI:Create("Label")
|
||||
local startindex = 0
|
||||
if (not startNpc.spawns) then
|
||||
return
|
||||
end
|
||||
for i in pairs(startNpc.spawns) do
|
||||
startindex = i
|
||||
end
|
||||
|
||||
if startindex == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local continent = QuestieJourneyUtils:GetZoneName(startindex)
|
||||
|
||||
startNPCZoneLabel:SetText(l10n(continent))
|
||||
startNPCZoneLabel:SetFullWidth(true)
|
||||
startNPCGroup:AddChild(startNPCZoneLabel)
|
||||
|
||||
local startx = startNpc.spawns[startindex][1][1]
|
||||
local starty = startNpc.spawns[startindex][1][2]
|
||||
if (startx ~= -1 or starty ~= -1) then
|
||||
local startNPCLocLabel = AceGUI:Create("Label")
|
||||
startNPCLocLabel:SetText("X: ".. startx .." || Y: ".. starty)
|
||||
startNPCLocLabel:SetFullWidth(true)
|
||||
startNPCGroup:AddChild(startNPCLocLabel)
|
||||
end
|
||||
|
||||
local startNPCIdLabel = AceGUI:Create("Label")
|
||||
startNPCIdLabel:SetText("NPC ID: ".. startNpc.id)
|
||||
startNPCIdLabel:SetFullWidth(true)
|
||||
startNPCGroup:AddChild(startNPCIdLabel)
|
||||
|
||||
QuestieJourneyUtils:Spacer(startNPCGroup)
|
||||
|
||||
-- Also Starts
|
||||
if startNpc.questStarts then
|
||||
|
||||
local alsoStartsLabel = AceGUI:Create("Label")
|
||||
alsoStartsLabel:SetText(l10n('This NPC Also Starts the following quests:'))
|
||||
alsoStartsLabel:SetColor(255, 165, 0)
|
||||
alsoStartsLabel:SetFontObject(GameFontHighlight)
|
||||
alsoStartsLabel:SetFullWidth(true)
|
||||
startNPCGroup:AddChild(alsoStartsLabel)
|
||||
|
||||
local startQuests = {}
|
||||
local counter = 1
|
||||
for _, v in pairs(startNpc.questStarts) do
|
||||
if v ~= quest.Id then
|
||||
startQuests[counter] = {}
|
||||
local startQuest = QuestieDB.GetQuest(v)
|
||||
local label = _QuestieJourney:GetInteractiveQuestLabel(startQuest)
|
||||
startQuests[counter].frame = label
|
||||
startQuests[counter].quest = startQuest
|
||||
startNPCGroup:AddChild(label)
|
||||
counter = counter + 1
|
||||
end
|
||||
end
|
||||
|
||||
if #startQuests == 0 then
|
||||
local noQuestLabel = AceGUI:Create("Label")
|
||||
noQuestLabel:SetText(l10n('No Quests to List'))
|
||||
noQuestLabel:SetFullWidth(true)
|
||||
startNPCGroup:AddChild(noQuestLabel)
|
||||
end
|
||||
end
|
||||
|
||||
QuestieJourneyUtils:Spacer(startNPCGroup)
|
||||
|
||||
end
|
||||
|
||||
-- Get Quest Start GameObject
|
||||
if quest.Starts and quest.Starts.GameObject then
|
||||
local startObjectGroup = AceGUI:Create("InlineGroup")
|
||||
startObjectGroup:SetLayout("List")
|
||||
startObjectGroup:SetTitle(l10n('Quest Start Object Information'))
|
||||
startObjectGroup:SetFullWidth(true)
|
||||
container:AddChild(startObjectGroup)
|
||||
|
||||
QuestieJourneyUtils:Spacer(startObjectGroup)
|
||||
|
||||
for _, oid in pairs(quest.Starts.GameObject) do
|
||||
local startObj = QuestieDB:GetObject(oid)
|
||||
|
||||
local startObjectNameLabel = AceGUI:Create("Label")
|
||||
startObjectNameLabel:SetText(startObj.name)
|
||||
startObjectNameLabel:SetFontObject(GameFontHighlight)
|
||||
startObjectNameLabel:SetColor(255, 165, 0)
|
||||
startObjectNameLabel:SetFullWidth(true)
|
||||
startObjectGroup:AddChild(startObjectNameLabel)
|
||||
|
||||
local startObjectZoneLabel = AceGUI:Create("Label")
|
||||
local startindex = 0
|
||||
for i in pairs(startObj.spawns) do
|
||||
startindex = i
|
||||
end
|
||||
|
||||
local continent = QuestieJourneyUtils:GetZoneName(startindex)
|
||||
|
||||
startObjectZoneLabel:SetText(continent)
|
||||
startObjectZoneLabel:SetFullWidth(true)
|
||||
startObjectGroup:AddChild(startObjectZoneLabel)
|
||||
|
||||
local startx = startObj.spawns[startindex][1][1]
|
||||
local starty = startObj.spawns[startindex][1][2]
|
||||
if (startx ~= -1 or starty ~= -1) then
|
||||
local startObjectLocLabel = AceGUI:Create("Label")
|
||||
startObjectLocLabel:SetText("X: ".. startx .." || Y: ".. starty)
|
||||
startObjectLocLabel:SetFullWidth(true)
|
||||
startObjectGroup:AddChild(startObjectLocLabel)
|
||||
end
|
||||
|
||||
local startObjectIdLabel = AceGUI:Create("Label")
|
||||
startObjectIdLabel:SetText("Object ID: ".. startObj.id)
|
||||
startObjectIdLabel:SetFullWidth(true)
|
||||
startObjectGroup:AddChild(startObjectIdLabel)
|
||||
|
||||
QuestieJourneyUtils:Spacer(startObjectGroup)
|
||||
|
||||
-- Also Starts
|
||||
if startObj.questStarts then
|
||||
|
||||
local alsoStartsLabel = AceGUI:Create("Label")
|
||||
alsoStartsLabel:SetText(l10n('This Object Also Starts the following quests:'))
|
||||
alsoStartsLabel:SetColor(255, 165, 0)
|
||||
alsoStartsLabel:SetFontObject(GameFontHighlight)
|
||||
alsoStartsLabel:SetFullWidth(true)
|
||||
startObjectGroup:AddChild(alsoStartsLabel)
|
||||
|
||||
local startQuests = {}
|
||||
local counter = 1
|
||||
for _, v in pairs(startObj.questStarts) do
|
||||
if v ~= quest.Id then
|
||||
startQuests[counter] = {}
|
||||
local startQuest = QuestieDB.GetQuest(v)
|
||||
local label = _QuestieJourney:GetInteractiveQuestLabel(startQuest)
|
||||
startQuests[counter].frame = label
|
||||
startQuests[counter].quest = startQuest
|
||||
startObjectGroup:AddChild(label)
|
||||
counter = counter + 1
|
||||
end
|
||||
end
|
||||
|
||||
if #startQuests == 0 then
|
||||
local noQuestLabel = AceGUI:Create("Label")
|
||||
noQuestLabel:SetText(l10n('No Quests to List'))
|
||||
noQuestLabel:SetFullWidth(true)
|
||||
startObjectGroup:AddChild(noQuestLabel)
|
||||
end
|
||||
end
|
||||
|
||||
QuestieJourneyUtils:Spacer(startObjectGroup)
|
||||
end
|
||||
end
|
||||
|
||||
QuestieJourneyUtils:Spacer(container)
|
||||
|
||||
if quest.Finisher and quest.Finisher.Name and quest.Finisher.Type == "monster" then
|
||||
local endNPCGroup = AceGUI:Create("InlineGroup")
|
||||
endNPCGroup:SetLayout("Flow")
|
||||
endNPCGroup:SetTitle(l10n('Quest Turn-in NPC Information'))
|
||||
endNPCGroup:SetFullWidth(true)
|
||||
container:AddChild(endNPCGroup)
|
||||
QuestieJourneyUtils:Spacer(endNPCGroup)
|
||||
|
||||
local endNPC = QuestieDB:GetNPC(quest.Finisher.Id)
|
||||
|
||||
local endNPCNameLabel = AceGUI:Create("Label")
|
||||
endNPCNameLabel:SetText(endNPC.name)
|
||||
endNPCNameLabel:SetFontObject(GameFontHighlight)
|
||||
endNPCNameLabel:SetColor(255, 165, 0)
|
||||
endNPCNameLabel:SetFullWidth(true)
|
||||
endNPCGroup:AddChild(endNPCNameLabel)
|
||||
|
||||
local endNPCZoneLabel = AceGUI:Create("Label")
|
||||
local endindex = 0
|
||||
if (not endNPC.spawns) then
|
||||
return
|
||||
end
|
||||
for i in pairs(endNPC.spawns) do
|
||||
endindex = i
|
||||
end
|
||||
|
||||
local continent = QuestieJourneyUtils:GetZoneName(endindex)
|
||||
|
||||
endNPCZoneLabel:SetText(l10n(continent))
|
||||
endNPCZoneLabel:SetFullWidth(true)
|
||||
endNPCGroup:AddChild(endNPCZoneLabel)
|
||||
|
||||
if (next(endNPC.spawns)) then
|
||||
local endx = endNPC.spawns[endindex][1][1]
|
||||
local endy = endNPC.spawns[endindex][1][2]
|
||||
if (endx ~= -1 or endy ~= -1) then
|
||||
local endNPCLocLabel = AceGUI:Create("Label")
|
||||
endNPCLocLabel:SetText("X: ".. endx .." || Y: ".. endy)
|
||||
endNPCLocLabel:SetFullWidth(true)
|
||||
endNPCGroup:AddChild(endNPCLocLabel)
|
||||
end
|
||||
end
|
||||
|
||||
local endNPCIdLabel = AceGUI:Create("Label")
|
||||
endNPCIdLabel:SetText("NPC ID: ".. endNPC.id)
|
||||
endNPCIdLabel:SetFullWidth(true)
|
||||
endNPCGroup:AddChild(endNPCIdLabel)
|
||||
|
||||
QuestieJourneyUtils:Spacer(endNPCGroup)
|
||||
|
||||
-- Also ends
|
||||
if endNPC.endQuests then
|
||||
local alsoEndsLabel = AceGUI:Create("Label")
|
||||
alsoEndsLabel:SetText(l10n('This NPC Also Completes the following quests:'))
|
||||
alsoEndsLabel:SetFontObject(GameFontHighlight)
|
||||
alsoEndsLabel:SetColor(255, 165, 0)
|
||||
alsoEndsLabel:SetFullWidth(true)
|
||||
endNPCGroup:AddChild(alsoEndsLabel)
|
||||
|
||||
local endQuests = {}
|
||||
local counter = 1
|
||||
for _, v in ipairs(endNPC.endQuests) do
|
||||
if v ~= quest.Id then
|
||||
endQuests[counter] = {}
|
||||
local endQuest = QuestieDB.GetQuest(v)
|
||||
local label = _QuestieJourney:GetInteractiveQuestLabel(endQuest)
|
||||
endQuests[counter].frame = label
|
||||
endQuests[counter].quest = endQuest
|
||||
endNPCGroup:AddChild(label)
|
||||
counter = counter + 1
|
||||
end
|
||||
end
|
||||
|
||||
if #endQuests == 0 then
|
||||
local noQuestLabel = AceGUI:Create("Label")
|
||||
noQuestLabel:SetText(l10n('No Quests to List'))
|
||||
noQuestLabel:SetFullWidth(true)
|
||||
endNPCGroup:AddChild(noQuestLabel)
|
||||
end
|
||||
|
||||
QuestieJourneyUtils:Spacer(endNPCGroup)
|
||||
end
|
||||
|
||||
-- Fix for sometimes the scroll content will max out and not show everything until window is resized
|
||||
container.content:SetHeight(10000)
|
||||
end
|
||||
end
|
||||
|
||||
---@param text string
|
||||
---@param fullWidth boolean
|
||||
---@return AceHeader
|
||||
function _QuestieJourney:CreateHeading(text, fullWidth)
|
||||
---@class AceHeader
|
||||
local header = AceGUI:Create("Heading")
|
||||
header:SetFullWidth(fullWidth)
|
||||
header:SetText(text)
|
||||
|
||||
return header
|
||||
end
|
||||
|
||||
---@param text string
|
||||
---@param fullWidth boolean
|
||||
---@return AceLabel
|
||||
function _QuestieJourney:CreateLabel(text, fullWidth)
|
||||
---@class AceLabel
|
||||
local header = AceGUI:Create("Label")
|
||||
header:SetFullWidth(fullWidth)
|
||||
header:SetText(text)
|
||||
|
||||
return header
|
||||
end
|
||||
|
||||
---@param questLevel number
|
||||
---@param questMinLevel number
|
||||
---@return string
|
||||
function _QuestieJourney:GetDifficultyString(questLevel, questMinLevel)
|
||||
local red, orange, yellow, green, gray = _QuestieJourney:GetLevelDifficultyRanges(questLevel, questMinLevel)
|
||||
local diffStr = ''
|
||||
|
||||
if red then
|
||||
diffStr = diffStr .. "|cFFFF1A1A[".. red .."]|r "
|
||||
end
|
||||
|
||||
if orange then
|
||||
diffStr = diffStr .. "|cFFFF8040[".. orange .."]|r "
|
||||
end
|
||||
|
||||
diffStr = diffStr .. "|cFFFFFF00[".. yellow .."]|r "
|
||||
diffStr = diffStr .. "|cFF40C040[".. green .."]|r "
|
||||
diffStr = diffStr .. "|cFFC0C0C0[".. gray .."]|r "
|
||||
|
||||
return Questie:Colorize(l10n('Difficulty Range: %s', diffStr), 'yellow')
|
||||
end
|
||||
|
||||
---@param quest Quest
|
||||
---@return number @The number of pre quests added to the group
|
||||
---@return AceInlineGroup @The created Ace InlineGroup
|
||||
function _QuestieJourney:CreatePreQuestGroup(quest)
|
||||
---@class AceInlineGroup
|
||||
local preQuestInlineGroup = AceGUI:Create("InlineGroup")
|
||||
local preQuestCounter = 1
|
||||
|
||||
preQuestInlineGroup:SetLayout("List")
|
||||
preQuestInlineGroup:SetTitle(l10n('Pre Quests'))
|
||||
preQuestInlineGroup:SetFullWidth(true)
|
||||
|
||||
if (quest.preQuestSingle and next(quest.preQuestSingle)) then
|
||||
for _, v in pairs(quest.preQuestSingle) do
|
||||
if v ~= quest.Id then
|
||||
local preQuest = QuestieDB.GetQuest(v)
|
||||
local label = _QuestieJourney:GetInteractiveQuestLabel(preQuest)
|
||||
preQuestInlineGroup:AddChild(label)
|
||||
preQuestCounter = preQuestCounter + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (quest.preQuestGroup and next(quest.preQuestGroup)) then
|
||||
for _, v in pairs(quest.preQuestGroup) do
|
||||
if v ~= quest.Id then
|
||||
local preQuest = QuestieDB.GetQuest(v)
|
||||
local label = _QuestieJourney:GetInteractiveQuestLabel(preQuest)
|
||||
preQuestInlineGroup:AddChild(label)
|
||||
preQuestCounter = preQuestCounter + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return preQuestCounter, preQuestInlineGroup
|
||||
end
|
||||
|
||||
---@param quest Quest
|
||||
---@return AceInteractiveLabel
|
||||
function _QuestieJourney:GetInteractiveQuestLabel(quest)
|
||||
---@class AceInteractiveLabel
|
||||
local label = AceGUI:Create("InteractiveLabel")
|
||||
local questId = quest.Id
|
||||
|
||||
label:SetText(QuestieLib:GetColoredQuestName(questId, Questie.db.profile.enableTooltipsQuestLevel, false, true))
|
||||
label:SetUserData('id', questId)
|
||||
label:SetUserData('name', quest.name)
|
||||
label:SetCallback("OnClick", function()
|
||||
ItemRefTooltip:SetHyperlink("%|Hquestie:" .. questId .. ":.*%|h", "%[%[" .. quest.level .. "%] " .. quest.name .. " %(" .. questId .. "%)%]")
|
||||
end)
|
||||
label:SetCallback("OnEnter", _QuestieJourney.ShowJourneyTooltip)
|
||||
label:SetCallback("OnLeave", _QuestieJourney.HideJourneyTooltip)
|
||||
|
||||
return label
|
||||
end
|
||||
@@ -0,0 +1,217 @@
|
||||
---@class QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:CreateModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
QuestieJourneyFrame = nil
|
||||
-------------------------
|
||||
--Import modules.
|
||||
-------------------------
|
||||
---@type QuestiePlayer
|
||||
local QuestiePlayer = QuestieLoader:ImportModule("QuestiePlayer")
|
||||
---@type QuestieOptions
|
||||
local QuestieOptions = QuestieLoader:ImportModule("QuestieOptions")
|
||||
---@type ZoneDB
|
||||
local ZoneDB = QuestieLoader:ImportModule("ZoneDB")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
---@type QuestieCombatQueue
|
||||
local QuestieCombatQueue = QuestieLoader:ImportModule("QuestieCombatQueue")
|
||||
|
||||
-- Useful doc about the AceGUI TreeGroup: https://github.com/hurricup/WoW-Ace3/blob/master/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
|
||||
|
||||
local tinsert = table.insert
|
||||
|
||||
QuestieJourney.continents = {}
|
||||
QuestieJourney.zones = {}
|
||||
QuestieJourney.tabGroup = nil
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
|
||||
local isWindowShown = false
|
||||
_QuestieJourney.lastOpenWindow = "journey"
|
||||
_QuestieJourney.lastZoneSelection = {}
|
||||
|
||||
local notesPopupWin
|
||||
local notesPopupWinIsOpen = false
|
||||
|
||||
QuestieJourney.questCategoryKeys = {
|
||||
EASTERN_KINGDOMS = 1,
|
||||
KALIMDOR = 2,
|
||||
OUTLAND = 3,
|
||||
NORTHREND = 4,
|
||||
DUNGEONS = 5,
|
||||
BATTLEGROUNDS = 6,
|
||||
CLASS = 7,
|
||||
PROFESSIONS = 8,
|
||||
EVENTS = 9,
|
||||
}
|
||||
|
||||
|
||||
function QuestieJourney:Initialize()
|
||||
local continents = {}
|
||||
for id, name in pairs(l10n.continentLookup) do
|
||||
if not (name == "Outland" and Questie.IsClassic) and not (name == "Northrend" and (Questie.IsClassic or Questie.IsTBC)) then
|
||||
continents[id] = l10n(name)
|
||||
end
|
||||
end
|
||||
coroutine.yield()
|
||||
continents[QuestieJourney.questCategoryKeys.CLASS] = QuestiePlayer:GetLocalizedClassName()
|
||||
|
||||
coroutine.yield()
|
||||
self.continents = continents
|
||||
self.zoneMap = ZoneDB:GetZonesWithQuests(true)
|
||||
self.zones = ZoneDB:GetRelevantZones()
|
||||
coroutine.yield()
|
||||
self:BuildMainFrame()
|
||||
end
|
||||
|
||||
function QuestieJourney:BuildMainFrame()
|
||||
if not QuestieJourneyFrame then
|
||||
local journeyFrame = AceGUI:Create("Frame")
|
||||
journeyFrame:SetCallback("OnClose", function()
|
||||
isWindowShown = false
|
||||
if notesPopupWinIsOpen then
|
||||
notesPopupWin:Hide()
|
||||
notesPopupWin = nil
|
||||
notesPopupWinIsOpen = false
|
||||
end
|
||||
end)
|
||||
journeyFrame:SetTitle(l10n("%s's Journey", UnitName("player")))
|
||||
journeyFrame:SetLayout("Fill")
|
||||
journeyFrame:EnableResize(false)
|
||||
QuestieCompat.SetResizeBounds(journeyFrame.frame, 550, 400)
|
||||
|
||||
local tabGroup = AceGUI:Create("TabGroup")
|
||||
tabGroup:SetLayout("Flow")
|
||||
tabGroup:SetTabs({
|
||||
{
|
||||
text = l10n('My Journey'),
|
||||
value="journey"
|
||||
},
|
||||
{
|
||||
text = l10n('Quests by Zone'),
|
||||
value="zone"
|
||||
},
|
||||
{
|
||||
text = l10n('Advanced Search'),
|
||||
value="search"
|
||||
}
|
||||
})
|
||||
tabGroup:SetCallback("OnGroupSelected", function(widget, _, group) _QuestieJourney:HandleTabChange(widget, group) end)
|
||||
tabGroup:SelectTab("journey")
|
||||
|
||||
QuestieJourney.tabGroup = tabGroup
|
||||
journeyFrame:AddChild(QuestieJourney.tabGroup)
|
||||
|
||||
local settingsButton = AceGUI:Create("Button")
|
||||
settingsButton:SetWidth(160)
|
||||
settingsButton:SetPoint("TOPRIGHT", journeyFrame.frame, "TOPRIGHT", -50, -13)
|
||||
settingsButton:SetText(l10n('Questie Options'))
|
||||
settingsButton:SetCallback("OnClick", function()
|
||||
QuestieCombatQueue:Queue(function()
|
||||
QuestieJourney:ToggleJourneyWindow()
|
||||
QuestieOptions:OpenConfigWindow()
|
||||
end)
|
||||
end)
|
||||
journeyFrame:AddChild(settingsButton)
|
||||
|
||||
journeyFrame:Hide()
|
||||
QuestieJourneyFrame = journeyFrame
|
||||
table.insert(UISpecialFrames, "QuestieJourneyFrame")
|
||||
end
|
||||
end
|
||||
|
||||
function QuestieJourney:IsShown()
|
||||
return isWindowShown
|
||||
end
|
||||
|
||||
function QuestieJourney:ToggleJourneyWindow()
|
||||
-- There are ways to toggle this function before the frame has been created
|
||||
if QuestieJourneyFrame then
|
||||
if (not isWindowShown) then
|
||||
PlaySound(882)
|
||||
|
||||
local treeGroup = _QuestieJourney:HandleTabChange(_QuestieJourney.containerCache, _QuestieJourney.lastOpenWindow)
|
||||
if treeGroup then
|
||||
_QuestieJourney.treeCache = treeGroup
|
||||
end
|
||||
|
||||
QuestieJourneyFrame:Show()
|
||||
isWindowShown = true
|
||||
else
|
||||
QuestieJourneyFrame:Hide()
|
||||
isWindowShown = false
|
||||
end
|
||||
else
|
||||
Questie:Error("QuestieJourney:ToggleJourneyWindow() called before QuestieJourneyFrame was initialized!")
|
||||
end
|
||||
end
|
||||
|
||||
function QuestieJourney:PlayerLevelUp(level)
|
||||
-- Complete Quest added to Journey
|
||||
---@type JourneyEntry
|
||||
local entry = {
|
||||
Event = "Level",
|
||||
NewLevel = level,
|
||||
Timestamp = time()
|
||||
}
|
||||
|
||||
tinsert(Questie.db.char.journey, entry)
|
||||
end
|
||||
|
||||
function QuestieJourney:AcceptQuest(questId)
|
||||
-- Add quest accept journey note.
|
||||
---@type JourneyEntry
|
||||
local entry = {
|
||||
Event = "Quest",
|
||||
SubType = "Accept",
|
||||
Quest = questId,
|
||||
Level = QuestiePlayer.GetPlayerLevel(),
|
||||
Timestamp = time()
|
||||
}
|
||||
|
||||
tinsert(Questie.db.char.journey, entry)
|
||||
end
|
||||
|
||||
function QuestieJourney:AbandonQuest(questId)
|
||||
-- Abandon Quest added to Journey
|
||||
-- first check to see if the quest has been completed already or not
|
||||
local skipAbandon = false
|
||||
for i in ipairs(Questie.db.char.journey) do
|
||||
|
||||
local entry = Questie.db.char.journey[i]
|
||||
if entry.Event == "Quest" then
|
||||
if entry.Quest == questId then
|
||||
if entry.SubType == "Complete" then
|
||||
skipAbandon = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not skipAbandon then
|
||||
---@type JourneyEntry
|
||||
local entry = {
|
||||
Event = "Quest",
|
||||
SubType = "Abandon",
|
||||
Quest = questId,
|
||||
Level = QuestiePlayer.GetPlayerLevel(),
|
||||
Timestamp = time()
|
||||
}
|
||||
|
||||
tinsert(Questie.db.char.journey, entry)
|
||||
end
|
||||
end
|
||||
|
||||
function QuestieJourney:CompleteQuest(questId)
|
||||
-- Complete Quest added to Journey
|
||||
---@class JourneyEntry
|
||||
local entry = {
|
||||
Event = "Quest",
|
||||
SubType = "Complete",
|
||||
Quest = questId,
|
||||
Level = QuestiePlayer.GetPlayerLevel(),
|
||||
Timestamp = time()
|
||||
}
|
||||
|
||||
tinsert(Questie.db.char.journey, entry)
|
||||
end
|
||||
@@ -0,0 +1,120 @@
|
||||
---@type QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:CreateModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
-------------------------
|
||||
--Import modules.
|
||||
-------------------------
|
||||
---@type QuestieSearchResults
|
||||
local QuestieSearchResults = QuestieLoader:ImportModule("QuestieSearchResults")
|
||||
---@type QuestieDB
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
_QuestieJourney.containerCache = nil
|
||||
_QuestieJourney.treeCache = nil
|
||||
|
||||
|
||||
function _QuestieJourney:ShowJourneyTooltip()
|
||||
if GameTooltip:IsShown() then
|
||||
return
|
||||
end
|
||||
local button = self -- ACE is doing something stupid here. Don't add "self" as parameter, when you use it as "_QuestieJourney.ShowJourneyTooltip" as callback
|
||||
|
||||
local qid = button:GetUserData('id')
|
||||
local quest = QuestieDB.GetQuest(tonumber(qid))
|
||||
if quest then
|
||||
GameTooltip:SetOwner(_G["QuestieJourneyFrame"].frame:GetParent(), "ANCHOR_CURSOR")
|
||||
GameTooltip:AddLine("[".. quest.level .."] ".. quest.name)
|
||||
GameTooltip:AddLine("|cFFFFFFFF" .. _QuestieJourney:CreateObjectiveText(quest.Description))
|
||||
GameTooltip:SetFrameStrata("TOOLTIP")
|
||||
GameTooltip:Show()
|
||||
end
|
||||
end
|
||||
|
||||
function _QuestieJourney:HideJourneyTooltip()
|
||||
if GameTooltip:IsShown() then
|
||||
GameTooltip:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
function _QuestieJourney:CreateObjectiveText(desc)
|
||||
local objText = ""
|
||||
|
||||
if desc then
|
||||
if type(desc) == "table" then
|
||||
for _, v in ipairs(desc) do
|
||||
objText = objText .. v .. "\n"
|
||||
end
|
||||
else
|
||||
objText = objText .. tostring(desc) .. "\n"
|
||||
end
|
||||
else
|
||||
objText = Questie:Colorize(l10n('This quest is an automatic completion quest and does not contain an objective.'), 'yellow')
|
||||
end
|
||||
|
||||
return objText
|
||||
end
|
||||
|
||||
function _QuestieJourney:HandleTabChange(container, group)
|
||||
if not _QuestieJourney.containerCache then
|
||||
_QuestieJourney.containerCache = container
|
||||
end
|
||||
|
||||
container:ReleaseChildren()
|
||||
|
||||
if group == "journey" then
|
||||
local treeGroup = _QuestieJourney.myJourney:DrawTab(container)
|
||||
_QuestieJourney.myJourney:ManageTree(treeGroup)
|
||||
_QuestieJourney.lastOpenWindow = "journey"
|
||||
return treeGroup
|
||||
elseif group == "zone" then
|
||||
_QuestieJourney.questsByZone:DrawTab(container)
|
||||
_QuestieJourney.lastOpenWindow = "zone"
|
||||
return nil
|
||||
elseif group == "search" then
|
||||
QuestieSearchResults:DrawSearchTab(container)
|
||||
_QuestieJourney.lastOpenWindow = "search"
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function _QuestieJourney:GetLevelDifficultyRanges(questLevel, questMinLevel)
|
||||
|
||||
local red, orange, yellow, green, gray
|
||||
|
||||
-- Calculate Base Values
|
||||
red = questMinLevel
|
||||
orange = questLevel - 4
|
||||
yellow = questLevel - 2
|
||||
green = questLevel + 3
|
||||
|
||||
-- Gray Level based on level range.
|
||||
if (questLevel <= 13) then
|
||||
gray = questLevel + 6
|
||||
elseif (questLevel <= 39) then
|
||||
gray = (questLevel + math.ceil(questLevel / 10) + 5)
|
||||
else
|
||||
gray = (questLevel + math.ceil(questLevel / 5) + 1)
|
||||
end
|
||||
|
||||
-- Double check for negative values
|
||||
if yellow <= 0 then
|
||||
yellow = questMinLevel
|
||||
end
|
||||
|
||||
if orange < questMinLevel then
|
||||
orange = questMinLevel
|
||||
end
|
||||
|
||||
if orange == yellow then
|
||||
orange = nil
|
||||
end
|
||||
|
||||
if red == orange or not orange then
|
||||
red = nil
|
||||
end
|
||||
|
||||
|
||||
return red, orange, yellow, green, gray
|
||||
end
|
||||
@@ -0,0 +1,67 @@
|
||||
---@class QuestieJourneyUtils
|
||||
local QuestieJourneyUtils = QuestieLoader:CreateModule("QuestieJourneyUtils")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0");
|
||||
|
||||
function QuestieJourneyUtils:GetSortedZoneKeys(zones)
|
||||
local function compare(a, b)
|
||||
return zones[a] < zones[b]
|
||||
end
|
||||
|
||||
local zoneNames = {}
|
||||
for k, _ in pairs(zones) do
|
||||
table.insert(zoneNames, k)
|
||||
end
|
||||
table.sort(zoneNames, compare)
|
||||
return zoneNames
|
||||
end
|
||||
|
||||
function QuestieJourneyUtils:Spacer(container, size)
|
||||
local spacer = AceGUI:Create("Label");
|
||||
spacer:SetFullWidth(true);
|
||||
spacer:SetText(" ");
|
||||
if size and size == "large" then
|
||||
spacer:SetFontObject(GameFontHighlightLarge);
|
||||
elseif size and size == "small" then
|
||||
spacer:SetFontObject(GameFontHighlightSmall);
|
||||
else
|
||||
spacer:SetFontObject(GameFontHighlight);
|
||||
end
|
||||
container:AddChild(spacer);
|
||||
end
|
||||
|
||||
function QuestieJourneyUtils:AddLine(frame, text)
|
||||
local label = AceGUI:Create("Label")
|
||||
label:SetFullWidth(true);
|
||||
label:SetText(text)
|
||||
label:SetFontObject(GameFontNormal)
|
||||
frame:AddChild(label)
|
||||
end
|
||||
|
||||
function QuestieJourneyUtils:GetZoneName(id)
|
||||
local name = l10n("Unknown Zone")
|
||||
for category, data in pairs(l10n.zoneLookup) do
|
||||
if data[id] then
|
||||
name = l10n.zoneLookup[category][id]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Ascension can use custom UiMapIds for zones/sub-zones (e.g. 1238 Northshire Valley).
|
||||
-- Those won't exist in l10n.zoneLookup (which is AreaId-based), so fallback to UiMapData / mapInfo.
|
||||
if name == l10n("Unknown Zone") then
|
||||
local uiMapData = QuestieCompat and QuestieCompat.UiMapData and QuestieCompat.UiMapData[id]
|
||||
if uiMapData and uiMapData.name then
|
||||
name = uiMapData.name
|
||||
elseif QuestieCompat and QuestieCompat.C_Map and QuestieCompat.C_Map.GetMapInfo then
|
||||
local mapInfo = QuestieCompat.C_Map.GetMapInfo(id)
|
||||
if mapInfo and mapInfo.name then
|
||||
name = mapInfo.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return name
|
||||
end
|
||||
@@ -0,0 +1,217 @@
|
||||
---@class QuestieSearch
|
||||
local QuestieSearch = QuestieLoader:CreateModule("QuestieSearch");
|
||||
|
||||
---@type QuestieDB
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
||||
|
||||
QuestieSearch.types = {"npc", "object", "item", "quest"}
|
||||
|
||||
-- Save search results, so the next search has a smaller set to search
|
||||
QuestieSearch.LastResult = {
|
||||
query = '',
|
||||
queryType = '',
|
||||
quest = {},
|
||||
npc = {},
|
||||
object = {},
|
||||
item = {},
|
||||
}
|
||||
local function _ResetResults()
|
||||
QuestieSearch.LastResult = {
|
||||
query = '',
|
||||
queryType = '',
|
||||
quest = {},
|
||||
npc = {},
|
||||
object = {},
|
||||
item = {},
|
||||
}
|
||||
end
|
||||
|
||||
-- Execute a search by name for all types
|
||||
function QuestieSearch:ByName(query)
|
||||
_ResetResults()
|
||||
for _, type in pairs(QuestieSearch.types) do
|
||||
QuestieSearch:Search(query, type, "chars")
|
||||
end
|
||||
return QuestieSearch.LastResult
|
||||
end
|
||||
|
||||
-- Execute a search by ID for all types
|
||||
function QuestieSearch:ByID(query)
|
||||
_ResetResults()
|
||||
for _,type in pairs(QuestieSearch.types) do
|
||||
QuestieSearch:Search(query, type, "int")
|
||||
end
|
||||
return QuestieSearch.LastResult
|
||||
end
|
||||
|
||||
--[[
|
||||
QuestieSearch:Search
|
||||
|
||||
This function searches a value from the database, including partial matches.
|
||||
|
||||
Adds the values to QuestieSearch.LastResult.
|
||||
|
||||
Returns table of found IDs for the selected search type.
|
||||
|
||||
Parameters:
|
||||
|
||||
query The search string/int
|
||||
|
||||
searchType Which database to search, possible values:
|
||||
"npc"
|
||||
"object"
|
||||
"item"
|
||||
"quest"
|
||||
|
||||
queryType Which type of search to run, possible values:
|
||||
"chars"
|
||||
"int"
|
||||
Optional. Default: "chars"
|
||||
--]]
|
||||
|
||||
function QuestieSearch:Search(rawQuery, searchType, queryType)
|
||||
queryType = queryType or "chars"
|
||||
|
||||
local databaseQueryHandle
|
||||
local databaseKeys
|
||||
local overrideKeys
|
||||
local ascensionKeys
|
||||
|
||||
if searchType == "npc" then
|
||||
databaseQueryHandle = QuestieDB.QueryNPCSingle
|
||||
databaseKeys = QuestieDB.NPCPointers
|
||||
overrideKeys = QuestieDB.npcDataOverrides
|
||||
ascensionKeys = QuestieDB.ascensionNpcIds
|
||||
elseif searchType == "object" then
|
||||
databaseQueryHandle = QuestieDB.QueryObjectSingle
|
||||
databaseKeys = QuestieDB.ObjectPointers
|
||||
overrideKeys = QuestieDB.objectDataOverrides
|
||||
ascensionKeys = QuestieDB.ascensionObjectIds
|
||||
elseif searchType == "item" then
|
||||
databaseQueryHandle = QuestieDB.QueryItemSingle
|
||||
databaseKeys = QuestieDB.ItemPointers
|
||||
overrideKeys = QuestieDB.itemDataOverrides
|
||||
ascensionKeys = QuestieDB.ascensionItemIds
|
||||
elseif searchType == "quest" then
|
||||
databaseQueryHandle = QuestieDB.QueryQuestSingle
|
||||
databaseKeys = QuestieDB.QuestPointers
|
||||
overrideKeys = QuestieDB.questDataOverrides
|
||||
ascensionKeys = QuestieDB.ascensionQuestIds
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
local sanitizedQuery
|
||||
local strictSearch = false
|
||||
if type(rawQuery) ~= "number" then
|
||||
local stringFirst, stringLast = rawQuery:sub(1, 1), rawQuery:sub(-1)
|
||||
if (stringFirst == '"' or stringFirst == "'") and (stringLast == stringFirst) then
|
||||
strictSearch = true
|
||||
sanitizedQuery = rawQuery:sub(2, -2)
|
||||
else
|
||||
sanitizedQuery = rawQuery
|
||||
end
|
||||
else
|
||||
sanitizedQuery = rawQuery
|
||||
end
|
||||
|
||||
local searchCount = 0;
|
||||
local isTextSearch = queryType == "chars"
|
||||
local isIdSearch = queryType == "int" and tonumber(sanitizedQuery) ~= nil
|
||||
|
||||
local lastResults = QuestieSearch.LastResult[searchType]
|
||||
|
||||
-- Fast-path for ID search: allow direct lookups even when the ID isn't in the compiled pointer tables
|
||||
-- (e.g. Ascension custom entries injected via *Overrides*).
|
||||
if isIdSearch then
|
||||
local directId = tonumber(sanitizedQuery)
|
||||
if directId then
|
||||
local directName = databaseQueryHandle(directId, "name")
|
||||
if directName then
|
||||
lastResults[directId] = true
|
||||
QuestieSearch.LastResult.query = rawQuery
|
||||
return lastResults
|
||||
end
|
||||
end
|
||||
end
|
||||
if isTextSearch then
|
||||
local queryToFind = string.lower(sanitizedQuery)
|
||||
local visited = {}
|
||||
|
||||
local function _RunNameMatch(id)
|
||||
local name = databaseQueryHandle(id, "name") -- Some entries don't have a 'name' because of the way we load corrections
|
||||
if strictSearch then
|
||||
if name and (string.lower(name) == queryToFind) then -- strict search
|
||||
searchCount = searchCount + 1;
|
||||
QuestieSearch.LastResult[searchType][id] = true;
|
||||
else
|
||||
QuestieSearch.LastResult[searchType][id] = nil;
|
||||
end
|
||||
else
|
||||
if name and string.find(string.lower(name), queryToFind) then -- fuzzy search
|
||||
searchCount = searchCount + 1;
|
||||
QuestieSearch.LastResult[searchType][id] = true;
|
||||
else
|
||||
QuestieSearch.LastResult[searchType][id] = nil;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if type(databaseKeys) == "table" then
|
||||
for id, _ in pairs(databaseKeys) do
|
||||
visited[id] = true
|
||||
_RunNameMatch(id)
|
||||
end
|
||||
end
|
||||
|
||||
-- Include custom data injected via overrides, since these IDs may not exist in *Pointers.
|
||||
if type(overrideKeys) == "table" then
|
||||
for id, _ in pairs(overrideKeys) do
|
||||
if not visited[id] then
|
||||
_RunNameMatch(id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Also include Ascension custom IDs
|
||||
if type(ascensionKeys) == "table" then
|
||||
for id, _ in pairs(ascensionKeys) do
|
||||
if not visited[id] then
|
||||
visited[id] = true
|
||||
_RunNameMatch(id)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif isIdSearch then
|
||||
-- Fast-path for custom data injected via overrides (may not exist in *Pointers)
|
||||
local qid = tonumber(sanitizedQuery)
|
||||
if qid and databaseQueryHandle(qid, "name") then
|
||||
lastResults[qid] = true
|
||||
searchCount = searchCount + 1
|
||||
end
|
||||
for id, _ in pairs(databaseKeys) do
|
||||
if strictSearch then
|
||||
if tostring(id) == sanitizedQuery then -- strict search
|
||||
-- We have a search result or a favourite to display
|
||||
searchCount = searchCount + 1;
|
||||
lastResults[id] = true;
|
||||
else
|
||||
-- This entry doesn't meet the search criteria, removed from the last results
|
||||
lastResults[id] = nil;
|
||||
end
|
||||
else
|
||||
if string.find(tostring(id), sanitizedQuery) then -- fuzzy search
|
||||
-- We have a search result or a favourite to display
|
||||
searchCount = searchCount + 1;
|
||||
lastResults[id] = true;
|
||||
else
|
||||
-- This entry doesn't meet the search criteria, removed from the last results
|
||||
lastResults[id] = nil;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
QuestieSearch.LastResult.query = rawQuery
|
||||
return QuestieSearch.LastResult[searchType]
|
||||
end
|
||||
@@ -0,0 +1,872 @@
|
||||
---@class QuestieSearchResults
|
||||
local QuestieSearchResults = QuestieLoader:CreateModule("QuestieSearchResults")
|
||||
-------------------------
|
||||
--Import modules.
|
||||
-------------------------
|
||||
---@type QuestieQuest
|
||||
local QuestieQuest = QuestieLoader:ImportModule("QuestieQuest")
|
||||
---@type QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:ImportModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
---@type QuestieJourneyUtils
|
||||
local QuestieJourneyUtils = QuestieLoader:ImportModule("QuestieJourneyUtils")
|
||||
---@type QuestieSearch
|
||||
local QuestieSearch = QuestieLoader:ImportModule("QuestieSearch")
|
||||
---@type QuestieMap
|
||||
local QuestieMap = QuestieLoader:ImportModule("QuestieMap")
|
||||
---@type QuestieDB
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
||||
---@type QuestieCorrections
|
||||
local QuestieCorrections = QuestieLoader:ImportModule("QuestieCorrections")
|
||||
---@type QuestieLib
|
||||
local QuestieLib = QuestieLoader:ImportModule("QuestieLib")
|
||||
---@type QuestieLink
|
||||
local QuestieLink = QuestieLoader:ImportModule("QuestieLink")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
local stringrep = string.rep
|
||||
local stringsub = string.sub
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0");
|
||||
|
||||
local _HandleOnGroupSelected
|
||||
local lastOpenSearch = "quest"
|
||||
local _selected = 0
|
||||
|
||||
local BY_NAME = 1
|
||||
local BY_ID = 2
|
||||
|
||||
|
||||
local function AddParagraph(frame, lookupObject, secondKey, header, query)
|
||||
if lookupObject[secondKey] then
|
||||
QuestieJourneyUtils:AddLine(frame, Questie:Colorize(header, "yellow"))
|
||||
for _,id in pairs(lookupObject[secondKey]) do
|
||||
local name = query(id, "name")
|
||||
if name then
|
||||
QuestieJourneyUtils:AddLine(frame, name.." ("..id..")")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Takes a frame and adds a paragraph with a header text and a list of links to other search results
|
||||
---@param frame AceGUIWidget The frame to work on
|
||||
---@param linkType string The type of result to link to (npc|object|quest|item)
|
||||
---@param lookupObject table Table of IDs (npc|object|quest|item)
|
||||
---@param header string The text header to show above the links
|
||||
---@param query function The function used to get link name from
|
||||
local function AddLinkedParagraph(frame, linkType, lookupObject, header, query)
|
||||
if lookupObject and #lookupObject > 0 then
|
||||
QuestieJourneyUtils:AddLine(frame, Questie:Colorize(header, "yellow"))
|
||||
for _,id in pairs(lookupObject) do
|
||||
-- QuestieJourneyUtils:AddLine(frame, lookupDB[id][lookupKey].." ("..id..")")
|
||||
local link = AceGUI:Create("InteractiveLabel")
|
||||
link:SetText(query(id, "name").." ("..id..")");
|
||||
link:SetCallback("OnClick", function() QuestieSearchResults:SetSearch(linkType, id) end)
|
||||
frame:AddChild(link);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Create a button for showing/hiding manual notes of NPCs/objects
|
||||
local function CreateShowHideButton(id)
|
||||
-- Initialise button
|
||||
local button = AceGUI:Create("Button")
|
||||
button.id = id
|
||||
if (not QuestieMap.manualFrames["any"]) or (not QuestieMap.manualFrames["any"][id]) then
|
||||
button:SetText(l10n("Show on Map"))
|
||||
button:SetCallback("OnClick", function(self) self:ShowOnMap(self) end)
|
||||
else
|
||||
button:SetText(l10n("Remove from Map"))
|
||||
button:SetCallback("OnClick", function(self) self:RemoveFromMap(self) end)
|
||||
end
|
||||
-- Functions for showing/hiding and switching behaviour afterwards
|
||||
button.RemoveFromMap = function(self)
|
||||
if self.idsToShow then
|
||||
for _, spawnId in pairs(self.idsToShow) do
|
||||
QuestieMap:UnloadManualFrames(spawnId)
|
||||
end
|
||||
else
|
||||
QuestieMap:UnloadManualFrames(self.id)
|
||||
end
|
||||
self:SetText(l10n("Show on Map"))
|
||||
self:SetCallback("OnClick", function() self:ShowOnMap(self) end)
|
||||
end
|
||||
button.ShowOnMap = function(self)
|
||||
if self.idsToShow then
|
||||
for _, spawnId in pairs(self.idsToShow) do
|
||||
if spawnId > 0 then
|
||||
QuestieMap:ShowNPC(spawnId)
|
||||
else
|
||||
QuestieMap:ShowObject(-spawnId)
|
||||
end
|
||||
end
|
||||
else
|
||||
if self.id > 0 then
|
||||
QuestieMap:ShowNPC(self.id)
|
||||
elseif self.id < 0 then
|
||||
QuestieMap:ShowObject(-self.id)
|
||||
end
|
||||
end
|
||||
self:SetText(l10n("Remove from Map"))
|
||||
self:SetCallback("OnClick", function() self:RemoveFromMap(self) end)
|
||||
end
|
||||
return button
|
||||
end
|
||||
|
||||
local function rec(theTable, ret, indent)
|
||||
ret = ret..stringrep(' ', indent)..'{\n'
|
||||
indent = indent + 1
|
||||
for k, v in pairs(theTable) do
|
||||
local t = type(v)
|
||||
if t == 'nil' then
|
||||
ret = ret..stringrep(' ', indent)..'['..k..']=nil'
|
||||
elseif t == 'table' then
|
||||
ret = rec(v, ret..stringrep(' ', indent)..'['..k..']=\n', indent)
|
||||
else
|
||||
ret = ret..stringrep(' ', indent)..'['..k..']='..v
|
||||
end
|
||||
ret = ret..'\n'
|
||||
end
|
||||
return ret..stringrep(' ', indent-1)..'},'
|
||||
end
|
||||
|
||||
local function recurseTable(theTable, theKeys)
|
||||
local ret = Questie:Colorize('Raw data (shown because debug is enabled):\n\n', 'red')
|
||||
for key, _ in pairs(theKeys) do
|
||||
ret = ret..Questie:Colorize(key, 'yellow')..': '
|
||||
local t = type(theTable[key])
|
||||
if t == 'nil' then
|
||||
ret = ret..'nil'
|
||||
elseif t == 'table' then
|
||||
ret = rec(theTable[key], ret, 0)
|
||||
else
|
||||
ret = ret..theTable[key]
|
||||
end
|
||||
ret = ret..'\n'
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function QuestieSearchResults:QuestDetailsFrame(details, id)
|
||||
local ret = QuestieDB.QueryQuest(id, {"name", "requiredLevel", "requiredRaces", "objectivesText", "startedBy", "finishedBy", "preQuestGroup", "preQuestSingle"}) or {}
|
||||
local name, requiredLevel, requiredRaces, objectivesText, startedBy, finishedBy, preQuestGroup, preQuestSingle = ret[1], ret[2], ret[3], ret[4], ret[5], ret[6], ret[7], ret[8]
|
||||
|
||||
local questLevel, _ = QuestieLib.GetTbcLevel(id);
|
||||
|
||||
-- header
|
||||
local title = AceGUI:Create("Heading")
|
||||
title:SetFullWidth(true);
|
||||
title:SetText(name)
|
||||
details:AddChild(title)
|
||||
|
||||
-- is quest finished by player
|
||||
local finished = AceGUI:Create("CheckBox")
|
||||
finished:SetValue(Questie.db.char.complete[id])
|
||||
finished:SetLabel(l10n("Complete"))
|
||||
finished:SetDisabled(true)
|
||||
-- reduce offset to next checkbox
|
||||
finished:SetHeight(16)
|
||||
details:AddChild(finished)
|
||||
|
||||
-- hidden by user
|
||||
local hiddenByUser = AceGUI:Create("CheckBox")
|
||||
hiddenByUser.id = id
|
||||
hiddenByUser:SetLabel(l10n("Hidden"))
|
||||
if Questie.db.char.hidden[id] ~= nil then
|
||||
hiddenByUser:SetValue(true)
|
||||
else
|
||||
hiddenByUser:SetValue(false)
|
||||
end
|
||||
hiddenByUser:SetCallback("OnValueChanged", function(frame)
|
||||
if Questie.db.char.hidden[frame.id] ~= nil then
|
||||
frame:SetValue(false)
|
||||
QuestieQuest:UnhideQuest(frame.id)
|
||||
else
|
||||
frame:SetValue(true)
|
||||
QuestieQuest:HideQuest(frame.id)
|
||||
end
|
||||
end)
|
||||
hiddenByUser:SetCallback("OnEnter", function()
|
||||
if GameTooltip:IsShown() then
|
||||
return;
|
||||
end
|
||||
GameTooltip:SetOwner(_G["QuestieJourneyFrame"].frame:GetParent(), "ANCHOR_CURSOR");
|
||||
GameTooltip:AddLine(l10n("Quest is hidden"))
|
||||
GameTooltip:AddLine(l10n("\nWhen selected, hides the quest from the map, even if it is active.\n\nHiding a quest is also possible by Shift-clicking it on the map."), 1, 1, 1, true);
|
||||
GameTooltip:SetFrameStrata("TOOLTIP");
|
||||
GameTooltip:Show();
|
||||
end)
|
||||
hiddenByUser:SetCallback("OnLeave", function()
|
||||
if GameTooltip:IsShown() then
|
||||
GameTooltip:Hide();
|
||||
end
|
||||
end)
|
||||
-- reduce offset to next checkbox
|
||||
hiddenByUser:SetHeight(16)
|
||||
details:AddChild(hiddenByUser)
|
||||
|
||||
-- hidden by Questie
|
||||
local hiddenQuests = AceGUI:Create("CheckBox")
|
||||
hiddenQuests:SetValue(QuestieCorrections.hiddenQuests[id])
|
||||
hiddenQuests:SetLabel(l10n("Hidden by Questie"))
|
||||
hiddenQuests:SetDisabled(true)
|
||||
-- do not reduce offset, as checkbox is followed by text
|
||||
details:AddChild(hiddenQuests)
|
||||
|
||||
-- general info
|
||||
QuestieJourneyUtils:AddLine(details, Questie:Colorize(l10n("Quest ID"), "yellow") .. ": " .. id)
|
||||
QuestieJourneyUtils:AddLine(details, Questie:Colorize(l10n("Quest Level"), "yellow") .. ": " .. questLevel)
|
||||
QuestieJourneyUtils:AddLine(details, Questie:Colorize(l10n("Required Level"), "yellow") .. ": " .. requiredLevel)
|
||||
local reqRaces = QuestieLib:GetRaceString(requiredRaces)
|
||||
if (reqRaces ~= "") then
|
||||
QuestieJourneyUtils:AddLine(details, Questie:Colorize(l10n("Required Race"), "yellow") .. ": " .. reqRaces)
|
||||
end
|
||||
QuestieJourneyUtils:AddLine(details, Questie:Colorize(l10n("Doable"), "yellow") .. ": " .. tostring(QuestieDB.IsDoableVerbose(id, false, true, true)))
|
||||
|
||||
-- objectives text
|
||||
if objectivesText then
|
||||
QuestieJourneyUtils:AddLine(details, "")
|
||||
QuestieJourneyUtils:AddLine(details, Questie:Colorize(l10n("Objectives"), "yellow") .. ":")
|
||||
for _, v in pairs(objectivesText) do
|
||||
QuestieJourneyUtils:AddLine(details, v)
|
||||
end
|
||||
end
|
||||
|
||||
if startedBy then
|
||||
-- quest starters
|
||||
QuestieJourneyUtils:AddLine(details, "")
|
||||
AddLinkedParagraph(details, "npc", startedBy[1], l10n("NPCs starting this quest:"), QuestieDB.QueryNPCSingle)
|
||||
AddLinkedParagraph(details, "object", startedBy[2], l10n("Objects starting this quest:"), QuestieDB.QueryObjectSingle)
|
||||
-- TODO change to linked paragraph once item details page exists
|
||||
AddParagraph(details, startedBy, 3, l10n("Items starting this quest:"), QuestieDB.QueryItemSingle)
|
||||
end
|
||||
if finishedBy then
|
||||
-- quest finishers
|
||||
QuestieJourneyUtils:AddLine(details, "")
|
||||
AddLinkedParagraph(details, "npc", finishedBy[1], l10n("NPCs finishing this quest:"), QuestieDB.QueryNPCSingle)
|
||||
AddLinkedParagraph(details, "object", finishedBy[2], l10n("Objects finishing this quest:"), QuestieDB.QueryObjectSingle)
|
||||
end
|
||||
|
||||
-- pre quests
|
||||
if preQuestGroup then
|
||||
QuestieJourneyUtils:AddLine(details, "")
|
||||
AddLinkedParagraph(details, "quest", preQuestGroup, l10n("Requires all of these quests to be finished:"), QuestieDB.QueryQuestSingle)
|
||||
end
|
||||
if preQuestSingle then
|
||||
QuestieJourneyUtils:AddLine(details, "")
|
||||
AddLinkedParagraph(details, "quest", preQuestSingle, l10n("Requires one of these quests to be finished:"), QuestieDB.QueryQuestSingle)
|
||||
end
|
||||
QuestieJourneyUtils:AddLine(details, "")
|
||||
|
||||
if Questie.db.profile.debugEnabled then
|
||||
QuestieJourneyUtils:AddLine(details, recurseTable(QuestieDB.GetQuest(id), QuestieDB.questKeys))
|
||||
end
|
||||
end
|
||||
|
||||
function QuestieSearchResults:SpawnDetailsFrame(f, spawn, spawnType)
|
||||
local header = AceGUI:Create("Heading");
|
||||
header:SetFullWidth(true);
|
||||
|
||||
local id = 0
|
||||
local typeLabel = ""
|
||||
local query
|
||||
if spawnType == "npc" then
|
||||
id = spawn
|
||||
typeLabel = "NPC"
|
||||
query = QuestieDB.QueryNPCSingle
|
||||
elseif spawnType == "object" then
|
||||
id = -spawn
|
||||
typeLabel = "Object"
|
||||
query = QuestieDB.QueryObjectSingle
|
||||
end
|
||||
|
||||
header:SetText(query(spawn, "name"));
|
||||
f:AddChild(header);
|
||||
|
||||
QuestieJourneyUtils:Spacer(f);
|
||||
|
||||
local spawnID = AceGUI:Create("Label");
|
||||
spawnID:SetText(typeLabel.." ID: "..spawn);
|
||||
spawnID:SetFullWidth(true);
|
||||
f:AddChild(spawnID);
|
||||
|
||||
QuestieJourneyUtils:Spacer(f);
|
||||
|
||||
local spawnZone = AceGUI:Create("Label");
|
||||
local spawns = query(spawn, "spawns")
|
||||
|
||||
if spawns then
|
||||
f:AddChild(CreateShowHideButton(id))
|
||||
local startindex = 0;
|
||||
for i in pairs(spawns) do
|
||||
if spawns[i][1] then
|
||||
startindex = i;
|
||||
break;
|
||||
end
|
||||
end
|
||||
|
||||
local zoneName = QuestieJourneyUtils:GetZoneName(startindex)
|
||||
|
||||
spawnZone:SetText(l10n(zoneName));
|
||||
spawnZone:SetFullWidth(true);
|
||||
f:AddChild(spawnZone);
|
||||
|
||||
if spawns[startindex] and spawns[startindex][1] then
|
||||
local startx = spawns[startindex][1][1];
|
||||
local starty = spawns[startindex][1][2];
|
||||
|
||||
if (startx ~= -1 or starty ~= -1) then
|
||||
local spawnLoc = AceGUI:Create("Label");
|
||||
spawnLoc:SetText("X: ".. startx .." || Y: ".. starty);
|
||||
spawnLoc:SetFullWidth(true);
|
||||
f:AddChild(spawnLoc);
|
||||
end
|
||||
end
|
||||
else
|
||||
spawnZone:SetText(l10n("No spawn data available."))
|
||||
spawnZone:SetFullWidth(true);
|
||||
f:AddChild(spawnZone);
|
||||
end
|
||||
|
||||
-- Also Starts
|
||||
local questStarts = query(spawn, "questStarts")
|
||||
if questStarts then
|
||||
local startGroup = AceGUI:Create("InlineGroup");
|
||||
startGroup:SetFullWidth(true);
|
||||
startGroup:SetLayout("flow");
|
||||
startGroup:SetTitle(l10n("Starts the following quests:"));
|
||||
f:AddChild(startGroup);
|
||||
|
||||
local startQuests = {};
|
||||
local counter = 1;
|
||||
for _, v in pairs(questStarts) do
|
||||
local quest = QuestieDB.GetQuest(v)
|
||||
local frame = AceGUI:Create("InteractiveLabel")
|
||||
frame:SetUserData("id", v)
|
||||
frame:SetUserData("name", quest.name)
|
||||
frame:SetCallback("OnClick", function() QuestieSearchResults:SetSearch("quest", v) end)
|
||||
frame:SetCallback("OnEnter", _QuestieJourney.ShowJourneyTooltip)
|
||||
frame:SetCallback("OnLeave", _QuestieJourney.HideJourneyTooltip)
|
||||
frame:SetText(QuestieLib:GetColoredQuestName(quest.Id, true, true))
|
||||
|
||||
startQuests[counter] = {
|
||||
frame = frame,
|
||||
quest = quest
|
||||
}
|
||||
startGroup:AddChild(frame)
|
||||
counter = counter + 1
|
||||
end
|
||||
|
||||
if #startQuests == 0 then
|
||||
local noquest = AceGUI:Create("Label");
|
||||
noquest:SetText(l10n("No quests to list."));
|
||||
noquest:SetFullWidth(true);
|
||||
startGroup:AddChild(noquest);
|
||||
end
|
||||
end
|
||||
|
||||
QuestieJourneyUtils:Spacer(f);
|
||||
|
||||
-- Also ends
|
||||
local questEnds = query(spawn, "questEnds")
|
||||
if questEnds then
|
||||
local endGroup = AceGUI:Create("InlineGroup");
|
||||
endGroup:SetFullWidth(true);
|
||||
endGroup:SetLayout("flow");
|
||||
endGroup:SetTitle(l10n("Ends the following quests:"));
|
||||
f:AddChild(endGroup);
|
||||
|
||||
local endQuests = {};
|
||||
local counter = 1;
|
||||
for _, v in ipairs(questEnds) do
|
||||
local quest = QuestieDB.GetQuest(v)
|
||||
local frame = AceGUI:Create("InteractiveLabel")
|
||||
frame:SetText(QuestieLib:GetColoredQuestName(quest.Id, true, true))
|
||||
frame:SetUserData("id", v)
|
||||
frame:SetUserData("name", quest.name)
|
||||
frame:SetCallback("OnClick", function() QuestieSearchResults:SetSearch("quest", v) end)
|
||||
frame:SetCallback("OnEnter", _QuestieJourney.ShowJourneyTooltip)
|
||||
frame:SetCallback("OnLeave", _QuestieJourney.HideJourneyTooltip)
|
||||
|
||||
endQuests[counter] = {
|
||||
frame = frame,
|
||||
quest = quest
|
||||
}
|
||||
endGroup:AddChild(frame)
|
||||
counter = counter + 1
|
||||
end
|
||||
|
||||
if #endQuests == 0 then
|
||||
local noquest = AceGUI:Create("Label");
|
||||
noquest:SetText(l10n("No quests to list."));
|
||||
noquest:SetFullWidth(true);
|
||||
endGroup:AddChild(noquest);
|
||||
end
|
||||
end
|
||||
|
||||
QuestieJourneyUtils:Spacer(f);
|
||||
|
||||
if Questie.db.profile.debugEnabled then
|
||||
if spawnType == "npc" then
|
||||
QuestieJourneyUtils:AddLine(f, recurseTable(QuestieDB:GetNPC(spawn), QuestieDB.npcKeys))
|
||||
elseif spawnType == "object" then
|
||||
QuestieJourneyUtils:AddLine(f, recurseTable(QuestieDB:GetObject(spawn), QuestieDB.objectKeys))
|
||||
end
|
||||
end
|
||||
|
||||
-- Fix for sometimes the scroll content will max out and not show everything until window is resized
|
||||
f.content:SetHeight(10000);
|
||||
end
|
||||
|
||||
function QuestieSearchResults:ItemDetailsFrame(f, itemId)
|
||||
local header = AceGUI:Create("Heading")
|
||||
header:SetFullWidth(true)
|
||||
|
||||
local query = QuestieDB.QueryItemSingle
|
||||
|
||||
header:SetText(query(itemId, "name"))
|
||||
f:AddChild(header)
|
||||
|
||||
local itemLink = select(2, GetItemInfo(itemId))
|
||||
local itemIcon = AceGUI:Create("Icon")
|
||||
itemIcon:SetWidth(25)
|
||||
itemIcon:SetHeight(25)
|
||||
itemIcon:SetImage(GetItemIcon(itemId))
|
||||
itemIcon:SetImageSize(25, 25)
|
||||
itemIcon:SetCallback("OnEnter", function()
|
||||
if (not itemLink) then
|
||||
itemLink = select(2, GetItemInfo(itemId))
|
||||
end
|
||||
GameTooltip:SetOwner(UIParent, "ANCHOR_CURSOR")
|
||||
if itemLink then
|
||||
GameTooltip:SetHyperlink(itemLink)
|
||||
elseif QuestieCompat.Is335 then
|
||||
-- I don't know if this applies to private servers, but let's assume it does.
|
||||
GameTooltip:AddLine("Item Unavailable", 1, 0, 0)
|
||||
GameTooltip:AddLine("This item is unsafe. To view this item without the risk of disconnection, you need to have first seen it in the game world. This is a restriction enforced by Blizzard since Patch 1.10.", nil, nil, nil, 1)
|
||||
GameTooltip:AddLine(" ");
|
||||
GameTooltip:AddLine("You can |cffFFFFFFLEFT-CLICK|r to attempt to query the server. You may be disconnected.", .75, .75, .75, 1)
|
||||
|
||||
itemIcon:SetCallback("OnClick", function()
|
||||
GameTooltip:SetHyperlink("item:"..itemId..":0:0:0:0:0:0:0")
|
||||
end)
|
||||
end
|
||||
GameTooltip:Show()
|
||||
end)
|
||||
itemIcon:SetCallback("OnLeave", function()
|
||||
GameTooltip:Hide()
|
||||
end)
|
||||
f:AddChild(itemIcon)
|
||||
|
||||
local spawnIdLabel = AceGUI:Create("Label")
|
||||
spawnIdLabel:SetText(" Item ID: " .. itemId)
|
||||
f:AddChild(spawnIdLabel)
|
||||
|
||||
if QuestieCorrections.questItemBlacklist[itemId] then
|
||||
QuestieJourneyUtils:Spacer(f)
|
||||
local itemBlacklistedLabel = AceGUI:Create("Label")
|
||||
itemBlacklistedLabel:SetText(l10n("This item is blacklisted because it has too many sources"))
|
||||
itemBlacklistedLabel:SetFullWidth(true)
|
||||
f:AddChild(itemBlacklistedLabel)
|
||||
return
|
||||
end
|
||||
|
||||
local sources = QuestieDB.QueryItem(itemId, {"npcDrops", "objectDrops", "vendors"})
|
||||
local npcDrops = sources[1]
|
||||
local objectDrops = sources[2]
|
||||
local vendors = sources[3]
|
||||
|
||||
local npcSpawnsHeading = AceGUI:Create("Heading")
|
||||
npcSpawnsHeading:SetText(l10n("NPCs"))
|
||||
npcSpawnsHeading:SetFullWidth(true)
|
||||
f:AddChild(npcSpawnsHeading)
|
||||
|
||||
if (not npcDrops or not next(npcDrops)) then
|
||||
local noNPCSourcesLabel = AceGUI:Create("Label")
|
||||
noNPCSourcesLabel:SetText(l10n("No NPC drops this item"))
|
||||
noNPCSourcesLabel:SetFullWidth(true)
|
||||
f:AddChild(noNPCSourcesLabel)
|
||||
else
|
||||
local npcLabel = AceGUI:Create("Label")
|
||||
|
||||
local npcIdsWithSpawns = {}
|
||||
for _, npcId in pairs(npcDrops) do
|
||||
local spawns = QuestieDB.QueryNPCSingle(npcId, "spawns")
|
||||
if spawns then
|
||||
npcIdsWithSpawns[#npcIdsWithSpawns + 1] = npcId
|
||||
end
|
||||
end
|
||||
|
||||
npcLabel:SetText(l10n("%d NPCs drop this item", #npcIdsWithSpawns))
|
||||
f:AddChild(npcLabel)
|
||||
if (#npcIdsWithSpawns > 0) then
|
||||
local showHideButton = CreateShowHideButton(itemId)
|
||||
showHideButton.idsToShow = npcIdsWithSpawns
|
||||
f:AddChild(showHideButton)
|
||||
end
|
||||
end
|
||||
|
||||
local objectSpawnsHeading = AceGUI:Create("Heading")
|
||||
objectSpawnsHeading:SetText(l10n("Objects"))
|
||||
objectSpawnsHeading:SetFullWidth(true)
|
||||
f:AddChild(objectSpawnsHeading)
|
||||
|
||||
if (not objectDrops or not next(objectDrops)) then
|
||||
local noObjectSourcesLabel = AceGUI:Create("Label")
|
||||
noObjectSourcesLabel:SetText(l10n("No Object drops this item"))
|
||||
noObjectSourcesLabel:SetFullWidth(true)
|
||||
f:AddChild(noObjectSourcesLabel)
|
||||
else
|
||||
local objectLabel = AceGUI:Create("Label")
|
||||
|
||||
local objectIdsWithSpawns = {}
|
||||
for _, objectId in pairs(objectDrops) do
|
||||
local spawns = QuestieDB.QueryObjectSingle(objectId, "spawns")
|
||||
if spawns then
|
||||
objectIdsWithSpawns[#objectIdsWithSpawns + 1] = -objectId
|
||||
end
|
||||
end
|
||||
|
||||
objectLabel:SetText(l10n("%d Objects drop this item", #objectIdsWithSpawns))
|
||||
f:AddChild(objectLabel)
|
||||
if (#objectIdsWithSpawns > 0) then
|
||||
local showHideButton = CreateShowHideButton(itemId)
|
||||
showHideButton.idsToShow = objectIdsWithSpawns
|
||||
f:AddChild(showHideButton)
|
||||
end
|
||||
end
|
||||
|
||||
local vendorSpawnsHeading = AceGUI:Create("Heading")
|
||||
vendorSpawnsHeading:SetText(l10n("Vendors"))
|
||||
vendorSpawnsHeading:SetFullWidth(true)
|
||||
f:AddChild(vendorSpawnsHeading)
|
||||
|
||||
if (not vendors or not next(vendors)) then
|
||||
local noVendorSourcesLabel = AceGUI:Create("Label")
|
||||
noVendorSourcesLabel:SetText(l10n("No Vendor sells this item"))
|
||||
noVendorSourcesLabel:SetFullWidth(true)
|
||||
f:AddChild(noVendorSourcesLabel)
|
||||
else
|
||||
local vendorLabel = AceGUI:Create("Label")
|
||||
|
||||
local vendorIdsWithSpawns = {}
|
||||
for _, npcId in pairs(vendors) do
|
||||
local spawns = QuestieDB.QueryNPCSingle(npcId, "spawns")
|
||||
|
||||
if spawns then
|
||||
vendorIdsWithSpawns[#vendorIdsWithSpawns + 1] = npcId
|
||||
end
|
||||
end
|
||||
|
||||
vendorLabel:SetText(l10n("%d Vendors sell this item", #vendorIdsWithSpawns))
|
||||
f:AddChild(vendorLabel)
|
||||
if (#vendorIdsWithSpawns > 0) then
|
||||
local showHideButton = CreateShowHideButton(itemId)
|
||||
showHideButton.idsToShow = vendorIdsWithSpawns
|
||||
f:AddChild(showHideButton)
|
||||
end
|
||||
end
|
||||
|
||||
if Questie.db.profile.debugEnabled then
|
||||
QuestieJourneyUtils:AddLine(f, recurseTable(QuestieDB:GetItem(itemId), QuestieDB.itemKeys))
|
||||
end
|
||||
-- Fix for sometimes the scroll content will max out and not show everything until window is resized
|
||||
f.content:SetHeight(10000);
|
||||
end
|
||||
|
||||
-- draws a list of results of a certain type, e.g. "quest"
|
||||
function QuestieSearchResults:DrawResultTab(container, resultType)
|
||||
-- probably already done by `JourneySelectTabGroup`, doesn't hurt to be safe though
|
||||
container:ReleaseChildren();
|
||||
|
||||
local results = {}
|
||||
local database
|
||||
if resultType == "quest" then
|
||||
database = QuestieDB.QueryQuestSingle
|
||||
elseif resultType == "npc" then
|
||||
database = QuestieDB.QueryNPCSingle
|
||||
elseif resultType == "object" then
|
||||
database = QuestieDB.QueryObjectSingle
|
||||
elseif resultType == "item" then
|
||||
database = QuestieDB.QueryItemSingle
|
||||
else
|
||||
return
|
||||
end
|
||||
for k,_ in pairs(QuestieSearch.LastResult[resultType]) do
|
||||
local name = database(k, "name")
|
||||
if name then
|
||||
local complete = ''
|
||||
if Questie.db.char.complete[k] and resultType == "quest" then
|
||||
complete = Questie:Colorize("(" .. l10n("Complete") .. ")" , "green")
|
||||
end
|
||||
-- TODO rename option to "enabledIDs" or create separate ones for npcs/objects/items
|
||||
local id = ''
|
||||
if Questie.db.profile.enableTooltipsQuestID then
|
||||
id = ' (' .. k .. ')'
|
||||
end
|
||||
table.insert(results, {
|
||||
["text"] = complete .. name .. id,
|
||||
["value"] = tonumber(k)
|
||||
})
|
||||
end
|
||||
end
|
||||
local resultFrame = AceGUI:Create("SimpleGroup");
|
||||
resultFrame:SetLayout("Fill");
|
||||
resultFrame:SetFullWidth(true);
|
||||
resultFrame:SetFullHeight(true);
|
||||
|
||||
local resultTree = AceGUI:Create("TreeGroup");
|
||||
resultTree:SetFullWidth(true);
|
||||
resultTree:SetFullHeight(true);
|
||||
resultTree.treeframe:SetWidth(260);
|
||||
resultTree:SetTree(results);
|
||||
resultTree:SetCallback("OnGroupSelected", _HandleOnGroupSelected)
|
||||
|
||||
resultFrame:AddChild(resultTree)
|
||||
container:AddChild(resultFrame);
|
||||
if _selected ~= 0 then
|
||||
resultTree:SelectByValue(_selected)
|
||||
_selected = 0
|
||||
end
|
||||
end
|
||||
|
||||
_HandleOnGroupSelected = function (resultType)
|
||||
-- This is either the questId, npcId, objectId or itemId
|
||||
local selectedId = tonumber(resultType.localstatus.selected)
|
||||
if IsShiftKeyDown() and lastOpenSearch == "quest" then
|
||||
local questName = QuestieDB.QueryQuestSingle(selectedId, "name")
|
||||
local questLevel, _ = QuestieLib.GetTbcLevel(selectedId);
|
||||
|
||||
ChatEdit_InsertLink(QuestieLink:GetQuestLinkString(questLevel, questName, selectedId))
|
||||
end
|
||||
|
||||
-- get master frame and create scroll frame inside
|
||||
local master = resultType.frame.obj;
|
||||
master:ReleaseChildren();
|
||||
master:SetLayout("Fill");
|
||||
master:SetFullWidth(true);
|
||||
master:SetFullHeight(true);
|
||||
|
||||
local details = AceGUI:Create("ScrollFrame");
|
||||
details:SetLayout("Flow");
|
||||
master:AddChild(details);
|
||||
|
||||
if lastOpenSearch == "quest" then
|
||||
QuestieSearchResults:QuestDetailsFrame(details, selectedId);
|
||||
elseif lastOpenSearch == "npc" then
|
||||
QuestieSearchResults:SpawnDetailsFrame(details, selectedId, 'npc');
|
||||
elseif lastOpenSearch == "object" then
|
||||
QuestieSearchResults:SpawnDetailsFrame(details, selectedId, 'object')
|
||||
elseif lastOpenSearch == "item" then
|
||||
QuestieSearchResults:ItemDetailsFrame(details, selectedId)
|
||||
end
|
||||
end
|
||||
|
||||
local function SelectTabGroup(container, _, resultType)
|
||||
lastOpenSearch = resultType
|
||||
QuestieSearchResults:DrawResultTab(container, resultType);
|
||||
end
|
||||
|
||||
local function _GetSearchFunction(searchBox, searchGroup)
|
||||
return function()
|
||||
if searchBox:GetText() ~= "" then
|
||||
local searchText = searchBox:GetText()
|
||||
|
||||
local itemName = GetItemInfo(searchText)
|
||||
if stringsub(searchText, 1, 4) == "|cff" and itemName then
|
||||
-- An itemLink was added to the searchBox
|
||||
searchBox:SetText(itemName)
|
||||
QuestieSearchResults:DrawSearchResultTab(searchGroup, Questie.db.profile.searchType, itemName, false)
|
||||
elseif stringsub(searchText, 1, 4) == "|cff" then
|
||||
-- This should be impossible to reach, since when you see an item link in the game the item should
|
||||
-- be cached already which would be caught by the condition above
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "Search with link of an uncached item")
|
||||
else
|
||||
-- Normal search
|
||||
local text = string.trim(searchText, " \n\r\t[]");
|
||||
QuestieSearchResults:DrawSearchResultTab(searchGroup, Questie.db.profile.searchType, text, false)
|
||||
end
|
||||
searchBox:ClearFocus()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Draw search results from advanced search tab
|
||||
local searchResultTabs
|
||||
function QuestieSearchResults:DrawSearchResultTab(searchGroup, searchType, query, useLast)
|
||||
if not searchResultTabs then
|
||||
searchGroup:ReleaseChildren();
|
||||
if searchType == BY_NAME and (not useLast) then
|
||||
QuestieSearch:ByName(query)
|
||||
elseif searchType == BY_ID and (not useLast) then
|
||||
QuestieSearch:ByID(query)
|
||||
end
|
||||
local results = QuestieSearch.LastResult;
|
||||
local resultTypes = {
|
||||
["quest"] = "Quests",
|
||||
["npc"] = "Mobs",
|
||||
["object"] = "Objects",
|
||||
["item"] = "Items",
|
||||
}
|
||||
local resultCountTotal = 0
|
||||
local resultCounts = {
|
||||
total = 0,
|
||||
quest = 0,
|
||||
npc = 0,
|
||||
object = 0,
|
||||
item = 0
|
||||
}
|
||||
for type,_ in pairs(resultTypes) do
|
||||
for _,_ in pairs(results[type]) do
|
||||
resultCountTotal = resultCountTotal + 1
|
||||
resultCounts[type] = resultCounts[type] + 1
|
||||
end
|
||||
end
|
||||
if (resultCountTotal == 0) then
|
||||
local noresults = AceGUI:Create("Label");
|
||||
noresults:SetText(Questie:Colorize(l10n('No Match for Search Results: %s', query), 'yellow'));
|
||||
noresults:SetFullWidth(true);
|
||||
searchGroup:AddChild(noresults);
|
||||
return;
|
||||
end
|
||||
searchResultTabs = AceGUI:Create("TabGroup");
|
||||
searchResultTabs:SetFullWidth(true);
|
||||
searchResultTabs:SetFullHeight(true);
|
||||
searchResultTabs:SetLayout("Flow");
|
||||
searchResultTabs:SetTabs({
|
||||
{
|
||||
text = l10n('Quests') .. " ("..resultCounts.quest..")",
|
||||
value = "quest",
|
||||
disabled = resultCounts.quest == 0,
|
||||
},
|
||||
{
|
||||
text = l10n('NPCs') .. " ("..resultCounts.npc..")",
|
||||
value = "npc",
|
||||
disabled = resultCounts.npc == 0,
|
||||
},
|
||||
{
|
||||
text = l10n('Objects') .. " ("..resultCounts.object..")",
|
||||
value = "object",
|
||||
disabled = resultCounts.object == 0,
|
||||
},
|
||||
{
|
||||
text = l10n('Items') .. " ("..resultCounts.item..")",
|
||||
value = "item",
|
||||
disabled = resultCounts.item == 0,
|
||||
},
|
||||
})
|
||||
searchResultTabs:SetCallback("OnGroupSelected", SelectTabGroup)
|
||||
if _selected == 0 then searchResultTabs:SelectTab("quest"); end
|
||||
searchGroup:AddChild(searchResultTabs);
|
||||
else
|
||||
searchGroup:ReleaseChildren();
|
||||
searchResultTabs = nil;
|
||||
self:DrawSearchResultTab(searchGroup, searchType, query, useLast);
|
||||
end
|
||||
end
|
||||
|
||||
-- The "Advanced Search" tab
|
||||
local typeDropdown
|
||||
local searchBox
|
||||
local searchGroup
|
||||
local searchButton
|
||||
function QuestieSearchResults:DrawSearchTab(container)
|
||||
-- Header
|
||||
local header = AceGUI:Create("Heading");
|
||||
header:SetText(l10n("Enter in your Search"));
|
||||
header:SetFullWidth(true);
|
||||
container:AddChild(header);
|
||||
QuestieJourneyUtils:Spacer(container);
|
||||
|
||||
searchBox = AceGUI:Create("EditBox");
|
||||
searchGroup = AceGUI:Create("SimpleGroup");
|
||||
searchButton = AceGUI:Create("Button");
|
||||
|
||||
typeDropdown = AceGUI:Create("Dropdown");
|
||||
typeDropdown:SetList({
|
||||
[1] = l10n("Search By Name"),
|
||||
[2] = l10n("Search By ID"),
|
||||
});
|
||||
typeDropdown:SetValue(Questie.db.profile.searchType);
|
||||
typeDropdown:SetCallback("OnValueChanged", function(key, _)
|
||||
Questie.db.profile.searchType = key.value;
|
||||
searchGroup:ReleaseChildren();
|
||||
searchBox:HighlightText();
|
||||
searchBox:SetFocus();
|
||||
end)
|
||||
container:AddChild(typeDropdown);
|
||||
|
||||
searchBox:SetFocus();
|
||||
searchBox:SetRelativeWidth(0.6);
|
||||
searchBox:SetLabel(l10n("Advanced Search") .. " (".. l10n("Quests") .. ", ".. l10n("NPCs") .. ", ".. l10n("Objects") .. ", ".. l10n("Items") .. ")");
|
||||
searchBox:DisableButton(true);
|
||||
searchBox:SetCallback("OnTextChanged", function()
|
||||
if searchBox:GetText() ~= "" then
|
||||
searchButton:SetDisabled(false);
|
||||
else
|
||||
searchButton:SetDisabled(true);
|
||||
end
|
||||
end);
|
||||
searchBox:SetCallback("OnEnterPressed", _GetSearchFunction(searchBox, searchGroup));
|
||||
-- Check for existence of previous search, if present use its text
|
||||
if QuestieSearch.LastResult.query ~= "" then
|
||||
searchBox:SetText(QuestieSearch.LastResult.query)
|
||||
end
|
||||
container:AddChild(searchBox);
|
||||
|
||||
searchButton:SetText(l10n("Search"));
|
||||
searchButton:SetDisabled(true);
|
||||
searchButton:SetCallback("OnClick", _GetSearchFunction(searchBox, searchGroup));
|
||||
container:AddChild(searchButton);
|
||||
|
||||
searchGroup:SetFullHeight(true);
|
||||
searchGroup:SetFullWidth(true);
|
||||
searchGroup:SetLayout("fill");
|
||||
container:AddChild(searchGroup);
|
||||
-- Check for existence of previous search, if present use its result
|
||||
if QuestieSearch.LastResult.query ~= "" then
|
||||
searchButton:SetDisabled(false)
|
||||
local text = string.trim(searchBox:GetText(), " \n\r\t[]")
|
||||
QuestieSearchResults:DrawSearchResultTab(searchGroup, Questie.db.profile.searchType, text, true)
|
||||
end
|
||||
end
|
||||
|
||||
function QuestieSearchResults:GetDetailFrame(detailType, id)
|
||||
local frame = AceGUI:Create("Frame")
|
||||
frame:SetHeight(500)
|
||||
frame:SetWidth(300)
|
||||
frame:SetLayout("Fill");
|
||||
local details = AceGUI:Create("ScrollFrame")
|
||||
details:SetFullWidth(true);
|
||||
details:SetFullHeight(true);
|
||||
details:SetLayout("Flow")
|
||||
frame:AddChild(details)
|
||||
if detailType == "quest" then
|
||||
QuestieSearchResults:QuestDetailsFrame(details, id)
|
||||
frame:SetTitle(l10n("Quest Details"))
|
||||
elseif detailType == "npc" then
|
||||
QuestieSearchResults:SpawnDetailsFrame(details, id, detailType)
|
||||
frame:SetTitle(l10n("NPC Details"))
|
||||
elseif detailType == "object" then
|
||||
QuestieSearchResults:SpawnDetailsFrame(details, id, detailType)
|
||||
frame:SetTitle(l10n("Object Details"))
|
||||
elseif detailType == "item" then
|
||||
QuestieSearchResults:ItemDetailsFrame(details, id)
|
||||
frame:SetTitle(l10n("Item Details"))
|
||||
else
|
||||
frame:ReleaseChildren()
|
||||
return
|
||||
end
|
||||
frame:Show()
|
||||
end
|
||||
|
||||
function QuestieSearchResults:SetSearch(detailType, id)
|
||||
_selected = id
|
||||
searchBox:SetText(tostring(id))
|
||||
Questie.db.profile.searchType = BY_ID
|
||||
typeDropdown:SetValue(BY_ID)
|
||||
QuestieSearchResults:DrawSearchResultTab(searchGroup, BY_ID, id, false)
|
||||
searchResultTabs:SelectTab(detailType)
|
||||
end
|
||||
@@ -0,0 +1,156 @@
|
||||
---@type QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:CreateModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
_QuestieJourney.myJourney = {}
|
||||
_QuestieJourney.notePopup = nil
|
||||
|
||||
---@type QuestieJourneyUtils
|
||||
local QuestieJourneyUtils = QuestieLoader:ImportModule("QuestieJourneyUtils")
|
||||
---@type QuestieDB
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
--- COMPATIBILITY ---
|
||||
local CALENDAR_WEEKDAY_NAMES = QuestieCompat.CALENDAR_WEEKDAY_NAMES
|
||||
local CALENDAR_FULLDATE_MONTH_NAMES = QuestieCompat.CALENDAR_FULLDATE_MONTH_NAMES
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0");
|
||||
local journeyTreeFrame
|
||||
|
||||
-- manage the journey tree
|
||||
function _QuestieJourney.myJourney:ManageTree(container)
|
||||
if not journeyTreeFrame then
|
||||
journeyTreeFrame = AceGUI:Create("TreeGroup");
|
||||
journeyTreeFrame:SetFullWidth(true);
|
||||
journeyTreeFrame:SetFullHeight(true);
|
||||
|
||||
journeyTreeFrame.treeframe:SetWidth(220);
|
||||
|
||||
local journeyTree = _QuestieJourney:GetHistory();
|
||||
journeyTreeFrame:SetTree(journeyTree);
|
||||
local latestMonth, latestYear = _QuestieJourney:GetMonthAndYearOfLatestEntry()
|
||||
if latestMonth and latestYear then
|
||||
journeyTreeFrame:SelectByPath(latestYear, latestMonth)
|
||||
end
|
||||
journeyTreeFrame:SetCallback("OnGroupSelected", function(group)
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[Journey] OnGroupSelected - Path:", group.localstatus.selected)
|
||||
|
||||
local _, _, e = strsplit("\001", group.localstatus.selected);
|
||||
|
||||
if e then
|
||||
local master = group.frame.obj;
|
||||
master:ReleaseChildren();
|
||||
master:SetLayout("fill");
|
||||
master:SetFullWidth(true);
|
||||
master:SetFullHeight(true);
|
||||
|
||||
local f = AceGUI:Create("ScrollFrame");
|
||||
f:SetLayout("flow");
|
||||
master:AddChild(f);
|
||||
|
||||
local header = AceGUI:Create("Heading");
|
||||
header:SetFullWidth(true);
|
||||
f:AddChild(header);
|
||||
|
||||
QuestieJourneyUtils:Spacer(f);
|
||||
|
||||
local created = AceGUI:Create("Label");
|
||||
created:SetFullWidth(true);
|
||||
|
||||
local entry = Questie.db.char.journey[tonumber(e)];
|
||||
local day = CALENDAR_WEEKDAY_NAMES[ tonumber(date('%w', entry.Timestamp)) + 1 ];
|
||||
local month = CALENDAR_FULLDATE_MONTH_NAMES[ tonumber(date('%m', entry.Timestamp)) ];
|
||||
local timestamp = Questie:Colorize(date( day ..', '.. month ..' %d @ %H:%M' , entry.Timestamp), 'blue');
|
||||
|
||||
if entry.Event == "Note" then
|
||||
header:SetText(l10n('Note: %s', entry.Title));
|
||||
|
||||
local note = AceGUI:Create("Label");
|
||||
note:SetFullWidth(true);
|
||||
note:SetText(Questie:Colorize( entry.Note , 'yellow'));
|
||||
f:AddChild(note);
|
||||
QuestieJourneyUtils:Spacer(f);
|
||||
|
||||
created:SetText(l10n('Note Created: %s', timestamp));
|
||||
f:AddChild(created);
|
||||
|
||||
elseif entry.Event == "Level" then
|
||||
header:SetText(l10n('You Reached Level %s', entry.NewLevel));
|
||||
|
||||
local congrats = AceGUI:Create("Label");
|
||||
congrats:SetText(l10n('Congratulations! You reached %s !', entry.NewLevel));
|
||||
congrats:SetFullWidth(true);
|
||||
f:AddChild(congrats);
|
||||
|
||||
created:SetText(timestamp);
|
||||
f:AddChild(created);
|
||||
|
||||
elseif entry.Event == "Quest" then
|
||||
local state
|
||||
if entry.SubType == "Accept" then
|
||||
state = l10n("Accepted");
|
||||
elseif entry.SubType == "Complete" then
|
||||
state = l10n("Completed");
|
||||
elseif entry.SubType == "Abandon" then
|
||||
state = l10n("Abandoned");
|
||||
else
|
||||
state = "ERROR!!";
|
||||
end
|
||||
|
||||
local quest = QuestieDB.GetQuest(entry.Quest)
|
||||
if quest then
|
||||
local qName = quest.name;
|
||||
header:SetText(l10n('Quest %s: %s', state, qName));
|
||||
|
||||
|
||||
local obj = AceGUI:Create("Label");
|
||||
obj:SetFullWidth(true);
|
||||
obj:SetText(_QuestieJourney:CreateObjectiveText(quest.Description));
|
||||
f:AddChild(obj);
|
||||
end
|
||||
|
||||
QuestieJourneyUtils:Spacer(f);
|
||||
|
||||
created:SetText(l10n('Quest %s: %s', state, timestamp));
|
||||
f:AddChild(created);
|
||||
|
||||
else
|
||||
header:SetText("ERROR!!");
|
||||
end
|
||||
|
||||
end
|
||||
end);
|
||||
|
||||
container:AddChild(journeyTreeFrame);
|
||||
else
|
||||
container:ReleaseChildren();
|
||||
journeyTreeFrame = nil;
|
||||
_QuestieJourney.myJourney:ManageTree(container);
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the month and year of the latest entry in the Journey.
|
||||
--- This is used to select it in the tree view.
|
||||
---@return number @The month of the latest entry
|
||||
---@return number @The year of the latest entry
|
||||
function _QuestieJourney:GetMonthAndYearOfLatestEntry()
|
||||
local journeyEntries = _QuestieJourney:GetJourneyEntries()
|
||||
local years = {}
|
||||
local months = {}
|
||||
|
||||
for year, _ in pairs(journeyEntries) do
|
||||
table.insert(years, year)
|
||||
end
|
||||
if not next(years) then
|
||||
return nil, nil
|
||||
end
|
||||
local maxYear = math.max(unpack(years))
|
||||
|
||||
for month, _ in pairs(journeyEntries[maxYear]) do
|
||||
table.insert(months, month)
|
||||
end
|
||||
local maxMonth = math.max(unpack(months))
|
||||
|
||||
return maxMonth, maxYear
|
||||
end
|
||||
@@ -0,0 +1,102 @@
|
||||
---@type QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:CreateModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
-------------------------
|
||||
--Import modules.
|
||||
-------------------------
|
||||
---@type QuestieJourneyUtils
|
||||
local QuestieJourneyUtils = QuestieLoader:ImportModule("QuestieJourneyUtils");
|
||||
---@type QuestieDB
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB");
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
--- COMPATIBILITY ---
|
||||
local CALENDAR_WEEKDAY_NAMES = QuestieCompat.CALENDAR_WEEKDAY_NAMES
|
||||
local CALENDAR_FULLDATE_MONTH_NAMES = QuestieCompat.CALENDAR_FULLDATE_MONTH_NAMES
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0");
|
||||
|
||||
--- Draw the "My Journey" tab
|
||||
---@param container Frame
|
||||
---@return SimpleGroup
|
||||
function _QuestieJourney.myJourney:DrawTab(container)
|
||||
local header = AceGUI:Create("Heading");
|
||||
header:SetText(l10n('Your Recent History'));
|
||||
header:SetFullWidth(true);
|
||||
container:AddChild(header);
|
||||
QuestieJourneyUtils:Spacer(container);
|
||||
|
||||
-- get last 5 elements from table for history
|
||||
local counter = #Questie.db.char.journey;
|
||||
local recentEvents = {};
|
||||
for i = counter, counter-4, -1 do
|
||||
if i <= 0 then
|
||||
break;
|
||||
end
|
||||
|
||||
recentEvents[i] = {};
|
||||
recentEvents[i] = AceGUI:Create("Label");
|
||||
recentEvents[i]:SetFullWidth(true);
|
||||
|
||||
local day = CALENDAR_WEEKDAY_NAMES[tonumber(date('%w', Questie.db.char.journey[i].Timestamp)) + 1];
|
||||
local month = CALENDAR_FULLDATE_MONTH_NAMES[tonumber(date('%m', Questie.db.char.journey[i].Timestamp))];
|
||||
|
||||
local timestamp = Questie:Colorize(date( '[ '..day ..', '.. month ..' %d @ %H:%M ] ' , Questie.db.char.journey[i].Timestamp), 'blue');
|
||||
|
||||
-- if it's a quest event
|
||||
if Questie.db.char.journey[i].Event == "Quest" then
|
||||
local qName = QuestieDB.QueryQuestSingle(Questie.db.char.journey[i].Quest, "name");
|
||||
if qName then
|
||||
qName = Questie:Colorize(qName, 'gray');
|
||||
|
||||
if Questie.db.char.journey[i].SubType == "Accept" then
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('You Accepted the quest %s', qName), 'yellow'));
|
||||
elseif Questie.db.char.journey[i].SubType == "Abandon" then
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('You Abandoned the quest %s', qName), 'yellow'));
|
||||
elseif Questie.db.char.journey[i].SubType == "Complete" then
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('You Completed the quest %s', qName), 'yellow'));
|
||||
end
|
||||
end
|
||||
elseif Questie.db.char.journey[i].Event == "Level" then
|
||||
local level = Questie:Colorize(l10n('Level %s', Questie.db.char.journey[i].NewLevel), 'gray');
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('Congratulations! You reached %s !', level), 'yellow'));
|
||||
elseif Questie.db.char.journey[i].Event == "Note" then
|
||||
local title = Questie:Colorize(Questie.db.char.journey[i].Title, 'gray');
|
||||
recentEvents[i]:SetText(timestamp .. Questie:Colorize(l10n('Note Created: %s', title), 'yellow'));
|
||||
end
|
||||
|
||||
container:AddChild(recentEvents[i]);
|
||||
end
|
||||
|
||||
if counter == 0 then
|
||||
local justdoit = AceGUI:Create("Label");
|
||||
justdoit:SetFullWidth(true);
|
||||
justdoit:SetText(Questie:Colorize(l10n("It's about time you embark on your first Journey!"), 'yellow'));
|
||||
container:AddChild(justdoit);
|
||||
end
|
||||
|
||||
QuestieJourneyUtils:Spacer(container);
|
||||
|
||||
local treeHeader = AceGUI:Create("Heading");
|
||||
treeHeader:SetText(l10n("%s's Journey", UnitName("player")));
|
||||
treeHeader:SetFullWidth(true);
|
||||
container:AddChild(treeHeader);
|
||||
|
||||
local noteButton = AceGUI:Create("Button");
|
||||
noteButton:SetText(l10n('Add New Adventure Note'));
|
||||
noteButton:SetPoint("RIGHT");
|
||||
noteButton:SetCallback("OnClick", _QuestieJourney.ShowNotePopup);
|
||||
container:AddChild(noteButton);
|
||||
|
||||
QuestieJourneyUtils:Spacer(container);
|
||||
|
||||
---@class SimpleGroup
|
||||
local treeGroup = AceGUI:Create("SimpleGroup");
|
||||
treeGroup:SetLayout("fill");
|
||||
treeGroup:SetFullHeight(true);
|
||||
treeGroup:SetFullWidth(true);
|
||||
container:AddChild(treeGroup);
|
||||
|
||||
return treeGroup
|
||||
end
|
||||
@@ -0,0 +1,132 @@
|
||||
---@type QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:CreateModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
_QuestieJourney.notePopup = nil
|
||||
-------------------------
|
||||
--Import modules
|
||||
-------------------------
|
||||
---@type QuestieJourneyUtils
|
||||
local QuestieJourneyUtils = QuestieLoader:ImportModule("QuestieJourneyUtils")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
--- COMPATIBILITY ---
|
||||
local CALENDAR_WEEKDAY_NAMES = QuestieCompat.CALENDAR_WEEKDAY_NAMES
|
||||
local CALENDAR_FULLDATE_MONTH_NAMES = QuestieCompat.CALENDAR_FULLDATE_MONTH_NAMES
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
local titleBox, messageBox
|
||||
|
||||
local _CreateNoteWindow, _CreateContainer, _CreateDescription, _CreateTitleBox, _CreateMessageBox
|
||||
local _CreateNoteAddButton, _HandleNoteEntry
|
||||
|
||||
|
||||
function _QuestieJourney:ShowNotePopup()
|
||||
if (not _QuestieJourney.notePopup) then
|
||||
_QuestieJourney.notePopup = _CreateNoteWindow()
|
||||
elseif (not _QuestieJourney.notePopup:IsShown()) then
|
||||
_QuestieJourney.notePopup:Show()
|
||||
else
|
||||
_QuestieJourney.notePopup:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
_CreateNoteWindow = function ()
|
||||
local notePopup = AceGUI:Create("Window")
|
||||
notePopup:Show()
|
||||
notePopup:SetTitle(l10n('Add New Adventure Note'))
|
||||
notePopup:SetWidth(400)
|
||||
notePopup:SetHeight(400)
|
||||
notePopup:EnableResize(false)
|
||||
notePopup.frame:SetFrameStrata(_QuestieJourney.containerCache.frame:GetFrameStrata())
|
||||
notePopup.frame:SetFrameLevel(_QuestieJourney.containerCache.frame:GetFrameLevel())
|
||||
notePopup.frame:Raise()
|
||||
notePopup:SetCallback("OnClose", function()
|
||||
notePopup:Hide()
|
||||
end)
|
||||
|
||||
local container = _CreateContainer()
|
||||
notePopup:AddChild(container)
|
||||
|
||||
local desc = _CreateDescription()
|
||||
container:AddChild(desc)
|
||||
|
||||
QuestieJourneyUtils:Spacer(container)
|
||||
|
||||
titleBox = _CreateTitleBox()
|
||||
container:AddChild(titleBox)
|
||||
|
||||
messageBox = _CreateMessageBox()
|
||||
container:AddChild(messageBox)
|
||||
|
||||
local addEntryBtn = _CreateNoteAddButton()
|
||||
container:AddChild(addEntryBtn)
|
||||
|
||||
return notePopup
|
||||
end
|
||||
|
||||
_CreateContainer = function ()
|
||||
-- Setup Note Taking
|
||||
local day = CALENDAR_WEEKDAY_NAMES[tonumber(date('%w', time())) + 1]
|
||||
local month = CALENDAR_FULLDATE_MONTH_NAMES[tonumber(date('%m', time()))]
|
||||
local today = date(day ..', '.. month ..' %d', time())
|
||||
local container = AceGUI:Create("InlineGroup")
|
||||
container:SetFullHeight(true)
|
||||
container:SetFullWidth(true)
|
||||
container:SetLayout('flow')
|
||||
container:SetTitle(l10n('New Note For: %s', today))
|
||||
return container
|
||||
end
|
||||
|
||||
_CreateDescription =function ()
|
||||
local desc = AceGUI:Create("Label")
|
||||
desc:SetText(Questie:Colorize(l10n('Create an entry in your journal to remember a specific moment. Simply supply a title and description and Questie will remember it for you!'), 'yellow'))
|
||||
desc:SetFullWidth(true)
|
||||
return desc
|
||||
end
|
||||
|
||||
_CreateTitleBox = function ()
|
||||
local box = AceGUI:Create("EditBox")
|
||||
box:SetFullWidth(true)
|
||||
box:SetLabel(l10n('Entry Title'))
|
||||
box:DisableButton(true)
|
||||
box:SetFocus()
|
||||
return box
|
||||
end
|
||||
|
||||
_CreateMessageBox = function ()
|
||||
local box = AceGUI:Create("MultiLineEditBox")
|
||||
box:SetFullWidth(true)
|
||||
box:SetNumLines(12)
|
||||
box:SetLabel(l10n('Journal Entry'))
|
||||
box:DisableButton(true)
|
||||
return box
|
||||
end
|
||||
|
||||
_CreateNoteAddButton = function ()
|
||||
local addEntryBtn = AceGUI:Create("Button")
|
||||
addEntryBtn:SetText(l10n('Add Entry'))
|
||||
addEntryBtn:SetCallback("OnClick", _HandleNoteEntry)
|
||||
return addEntryBtn
|
||||
end
|
||||
|
||||
_HandleNoteEntry = function ()
|
||||
local error = Questie:Colorize('[Questie] ', 'blue')
|
||||
if titleBox:GetText() == '' then
|
||||
print (error .. l10n('No Title was entered. You must enter a title before submitting your note.'))
|
||||
return
|
||||
elseif messageBox:GetText() == '' then
|
||||
print (error .. l10n('No Note was entered. You must enter a note before submitting.'))
|
||||
return
|
||||
end
|
||||
local data = {}
|
||||
data.Event = "Note"
|
||||
data.Note = messageBox:GetText()
|
||||
data.Title = titleBox:GetText()
|
||||
data.Timestamp = time()
|
||||
|
||||
tinsert(Questie.db.char.journey, data)
|
||||
|
||||
_QuestieJourney.myJourney:ManageTree(_QuestieJourney.treeCache)
|
||||
_QuestieJourney.notePopup:Hide()
|
||||
end
|
||||
@@ -0,0 +1,236 @@
|
||||
---@type QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:CreateModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
_QuestieJourney.questsByZone = {}
|
||||
|
||||
---@type QuestieDB
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
||||
---@type QuestieLib
|
||||
local QuestieLib = QuestieLoader:ImportModule("QuestieLib")
|
||||
---@type QuestieReputation
|
||||
local QuestieReputation = QuestieLoader:ImportModule("QuestieReputation")
|
||||
---@type QuestieCorrections
|
||||
local QuestieCorrections = QuestieLoader:ImportModule("QuestieCorrections")
|
||||
---@type QuestieEvent
|
||||
local QuestieEvent = QuestieLoader:ImportModule("QuestieEvent")
|
||||
---@type QuestieLink
|
||||
local QuestieLink = QuestieLoader:ImportModule("QuestieLink")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
local zoneTreeFrame
|
||||
|
||||
---Manage the zone tree itself and the contents of the per-quest window
|
||||
---@param container AceSimpleGroup @The container for the zone tree
|
||||
---@param zoneTree table @The zone tree table
|
||||
function _QuestieJourney.questsByZone:ManageTree(container, zoneTree)
|
||||
if zoneTreeFrame then
|
||||
container:ReleaseChildren()
|
||||
zoneTreeFrame = nil
|
||||
_QuestieJourney.questsByZone:ManageTree(container, zoneTree)
|
||||
return
|
||||
end
|
||||
|
||||
zoneTreeFrame = AceGUI:Create("TreeGroup")
|
||||
zoneTreeFrame:SetFullWidth(true)
|
||||
zoneTreeFrame:SetFullHeight(true)
|
||||
zoneTreeFrame:SetTree(zoneTree)
|
||||
|
||||
zoneTreeFrame.treeframe:SetWidth(220)
|
||||
zoneTreeFrame:SetCallback("OnClick", function(group, ...)
|
||||
local treePath = {...}
|
||||
|
||||
if not treePath[2] then
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[zoneTreeFrame:OnClick] No tree path given in Journey.")
|
||||
return
|
||||
end
|
||||
-- if they clicked on a header, don't do anything
|
||||
local sel, questId = strsplit("\001", treePath[2]) -- treePath[2] looks like "a?1234" for an available quest with ID 1234
|
||||
if (sel == nil or sel == "a" or sel == "p" or sel == "c" or sel == "r" or sel == "u") and (not questId) then
|
||||
return
|
||||
end
|
||||
|
||||
-- get master frame and create scroll frame inside
|
||||
local master = group.frame.obj
|
||||
master:ReleaseChildren()
|
||||
master:SetLayout("fill")
|
||||
master:SetFullWidth(true)
|
||||
master:SetFullHeight(true)
|
||||
|
||||
---@class ScrollFrame
|
||||
local scrollFrame = AceGUI:Create("ScrollFrame")
|
||||
scrollFrame:SetLayout("flow")
|
||||
scrollFrame:SetFullHeight(true)
|
||||
master:AddChild(scrollFrame)
|
||||
|
||||
---@type number
|
||||
questId = tonumber(questId)
|
||||
local quest = QuestieDB.GetQuest(questId)
|
||||
|
||||
-- Add the quest to the open chat window if it was a shift click
|
||||
if (IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow()) then
|
||||
ChatEdit_InsertLink(QuestieLink:GetQuestLinkString(quest.level, quest.name, quest.Id))
|
||||
end
|
||||
|
||||
_QuestieJourney:DrawQuestDetailsFrame(scrollFrame, quest)
|
||||
end)
|
||||
|
||||
container:AddChild(zoneTreeFrame)
|
||||
end
|
||||
|
||||
---Get all the available/completed/repeatable/unavailable quests
|
||||
---@param zoneId number @The zone ID (Check `l10n.zoneLookup`)
|
||||
---@return table<number,any> @The zoneTree table which represents the list of all the different quests
|
||||
function _QuestieJourney.questsByZone:CollectZoneQuests(zoneId)
|
||||
local quests = QuestieJourney.zoneMap[zoneId]--QuestieDB:GetQuestsByZoneId(zoneId)
|
||||
|
||||
if (not quests) then
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
local zoneTree = {
|
||||
[1] = {
|
||||
value = "a",
|
||||
text = l10n('Available Quests'),
|
||||
children = {}
|
||||
},
|
||||
[2] = {
|
||||
value = "p",
|
||||
text = l10n('Missing Pre Quest'),
|
||||
children = {}
|
||||
},
|
||||
[3] = {
|
||||
value = "c",
|
||||
text = l10n('Completed Quests'),
|
||||
children = {}
|
||||
},
|
||||
[4] = {
|
||||
value = "r",
|
||||
text = l10n('Repeatable Quests'),
|
||||
children = {},
|
||||
},
|
||||
[5] = {
|
||||
value = "u",
|
||||
text = l10n('Unobtainable Quests'),
|
||||
children = {},
|
||||
}
|
||||
}
|
||||
local sortedQuestByLevel = QuestieLib:SortQuestIDsByLevel(quests)
|
||||
|
||||
local availableCounter = 0
|
||||
local prequestMissingCounter = 0
|
||||
local completedCounter = 0
|
||||
local unobtainableCounter = 0
|
||||
local repeatableCounter = 0
|
||||
|
||||
local unobtainableQuestIds = {}
|
||||
local temp = {}
|
||||
|
||||
for _, levelAndQuest in pairs(sortedQuestByLevel) do
|
||||
---@type number
|
||||
local questId = levelAndQuest[2]
|
||||
-- Only show quests which are not hidden
|
||||
local isStreamQuest = QuestieDB.QuestPointers and QuestieDB.QuestPointers[questId]
|
||||
local isAscensionQuest = QuestieDB.ascensionQuestIds and QuestieDB.ascensionQuestIds[questId]
|
||||
|
||||
if QuestieCorrections.hiddenQuests
|
||||
and ((not QuestieCorrections.hiddenQuests[questId]) or QuestieEvent:IsEventQuest(questId))
|
||||
and (isStreamQuest or isAscensionQuest) then
|
||||
|
||||
temp.value = questId
|
||||
temp.text = QuestieLib:GetColoredQuestName(questId, Questie.db.profile.enableTooltipsQuestLevel, false, true)
|
||||
|
||||
-- Completed quests
|
||||
if Questie.db.char.complete[questId] then
|
||||
tinsert(zoneTree[3].children, temp)
|
||||
completedCounter = completedCounter + 1
|
||||
else
|
||||
local queryResult = QuestieDB.QueryQuest(
|
||||
questId,
|
||||
{
|
||||
"exclusiveTo",
|
||||
"nextQuestInChain",
|
||||
"parentQuest",
|
||||
"preQuestSingle",
|
||||
"preQuestGroup",
|
||||
"requiredMinRep",
|
||||
"requiredMaxRep"
|
||||
}
|
||||
) or {}
|
||||
local exclusiveTo = queryResult[1]
|
||||
local nextQuestInChain = queryResult[2]
|
||||
local parentQuest = queryResult[3]
|
||||
local preQuestSingle = queryResult[4]
|
||||
local preQuestGroup = queryResult[5]
|
||||
local requiredMinRep = queryResult[6]
|
||||
local requiredMaxRep = queryResult[7]
|
||||
|
||||
-- Exclusive quests will never be available since another quests permanently blocks them.
|
||||
-- Marking them as complete should be the most satisfying solution for user
|
||||
if (nextQuestInChain and Questie.db.char.complete[nextQuestInChain]) or (exclusiveTo and QuestieDB:IsExclusiveQuestInQuestLogOrComplete(exclusiveTo)) then
|
||||
tinsert(zoneTree[3].children, temp)
|
||||
completedCounter = completedCounter + 1
|
||||
-- The parent quest has been completed
|
||||
elseif parentQuest and Questie.db.char.complete[parentQuest] then
|
||||
tinsert(zoneTree[3].children, temp)
|
||||
completedCounter = completedCounter + 1
|
||||
-- Unoptainable reputation quests
|
||||
elseif not QuestieReputation:HasReputation(requiredMinRep, requiredMaxRep) then
|
||||
tinsert(zoneTree[5].children, temp)
|
||||
unobtainableQuestIds[questId] = true
|
||||
unobtainableCounter = unobtainableCounter + 1
|
||||
-- A single pre Quest is missing
|
||||
elseif not QuestieDB:IsPreQuestSingleFulfilled(preQuestSingle) then
|
||||
-- The pre Quest is unobtainable therefore this quest is it as well
|
||||
if unobtainableQuestIds[preQuestSingle] ~= nil then
|
||||
tinsert(zoneTree[5].children, temp)
|
||||
unobtainableQuestIds[questId] = true
|
||||
unobtainableCounter = unobtainableCounter + 1
|
||||
else
|
||||
tinsert(zoneTree[2].children, temp)
|
||||
prequestMissingCounter = prequestMissingCounter + 1
|
||||
end
|
||||
-- Multiple pre Quests are missing
|
||||
elseif not QuestieDB:IsPreQuestGroupFulfilled(preQuestGroup) then
|
||||
local hasUnobtainablePreQuest = false
|
||||
for _, preQuestId in pairs(preQuestGroup) do
|
||||
if unobtainableQuestIds[preQuestId] ~= nil then
|
||||
tinsert(zoneTree[5].children, temp)
|
||||
unobtainableQuestIds[questId] = true
|
||||
unobtainableCounter = unobtainableCounter + 1
|
||||
hasUnobtainablePreQuest = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not hasUnobtainablePreQuest then
|
||||
tinsert(zoneTree[2].children, temp)
|
||||
prequestMissingCounter = prequestMissingCounter + 1
|
||||
end
|
||||
-- Repeatable quests
|
||||
elseif QuestieDB.IsRepeatable(questId) then
|
||||
tinsert(zoneTree[4].children, temp)
|
||||
repeatableCounter = repeatableCounter + 1
|
||||
-- Available quests
|
||||
else
|
||||
tinsert(zoneTree[1].children, temp)
|
||||
availableCounter = availableCounter + 1
|
||||
end
|
||||
end
|
||||
temp = {}
|
||||
end
|
||||
end
|
||||
|
||||
local totalCounter = availableCounter + completedCounter + prequestMissingCounter
|
||||
zoneTree[1].text = zoneTree[1].text .. ' [ '.. availableCounter ..'/'.. totalCounter ..' ]'
|
||||
zoneTree[2].text = zoneTree[2].text .. ' [ '.. prequestMissingCounter ..'/'.. totalCounter ..' ]'
|
||||
zoneTree[3].text = zoneTree[3].text .. ' [ '.. completedCounter ..'/'.. totalCounter ..' ]'
|
||||
zoneTree[4].text = zoneTree[4].text .. ' [ '.. repeatableCounter ..' ]'
|
||||
zoneTree[5].text = zoneTree[5].text .. ' [ '.. unobtainableCounter ..' ]'
|
||||
|
||||
zoneTree.numquests = totalCounter + repeatableCounter + unobtainableCounter
|
||||
|
||||
return zoneTree
|
||||
end
|
||||
@@ -0,0 +1,165 @@
|
||||
---@type QuestieJourney
|
||||
local QuestieJourney = QuestieLoader:CreateModule("QuestieJourney")
|
||||
local _QuestieJourney = QuestieJourney.private
|
||||
-------------------------
|
||||
--Import modules.
|
||||
-------------------------
|
||||
---@type QuestieJourneyUtils
|
||||
local QuestieJourneyUtils = QuestieLoader:ImportModule("QuestieJourneyUtils")
|
||||
---@type QuestiePlayer
|
||||
local QuestiePlayer = QuestieLoader:ImportModule("QuestiePlayer")
|
||||
---@type QuestieProfessions
|
||||
local QuestieProfessions = QuestieLoader:ImportModule("QuestieProfessions")
|
||||
---@type QuestieDB
|
||||
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
|
||||
local RESET = -1000
|
||||
|
||||
local _CreateContinentDropdown, _CreateZoneDropdown
|
||||
local _HandleContinentSelection, _HandleZoneSelection
|
||||
|
||||
local selectedContinentId
|
||||
local contDropdown, zoneDropdown, treegroup
|
||||
|
||||
-- function that draws the Tab for Zone Quests
|
||||
function _QuestieJourney.questsByZone:DrawTab(container)
|
||||
---@class AceSimpleGroup
|
||||
treegroup = AceGUI:Create("SimpleGroup")
|
||||
|
||||
-- Header
|
||||
local header = AceGUI:Create("Heading")
|
||||
header:SetText(l10n('Select Your Continent and Zone'))
|
||||
header:SetFullWidth(true)
|
||||
container:AddChild(header)
|
||||
|
||||
QuestieJourneyUtils:Spacer(container)
|
||||
|
||||
contDropdown = _CreateContinentDropdown()
|
||||
container:AddChild(contDropdown)
|
||||
|
||||
zoneDropdown = _CreateZoneDropdown()
|
||||
container:AddChild(zoneDropdown)
|
||||
|
||||
QuestieJourneyUtils:Spacer(container)
|
||||
|
||||
header = AceGUI:Create("Heading")
|
||||
header:SetText(l10n('Zone Quests'))
|
||||
header:SetFullWidth(true)
|
||||
container:AddChild(header)
|
||||
|
||||
QuestieJourneyUtils:Spacer(container)
|
||||
|
||||
treegroup:SetFullHeight(true)
|
||||
treegroup:SetFullWidth(true)
|
||||
treegroup:SetLayout("fill")
|
||||
container:AddChild(treegroup)
|
||||
end
|
||||
|
||||
_CreateContinentDropdown = function()
|
||||
local dropdown = AceGUI:Create("Dropdown")
|
||||
dropdown:SetList(QuestieJourney.continents)
|
||||
dropdown:SetText(l10n('Select Your Continent'))
|
||||
dropdown:SetCallback("OnValueChanged", _HandleContinentSelection)
|
||||
|
||||
local currentContinentId = QuestiePlayer:GetCurrentContinentId()
|
||||
|
||||
-- This mapping translates the actual continent ID to the keys of l10n.continentLookup
|
||||
if currentContinentId == 0 then -- Eastern Kingdom
|
||||
selectedContinentId = 1
|
||||
elseif currentContinentId == 1 then -- Kalimdor
|
||||
selectedContinentId = 2
|
||||
elseif currentContinentId == 530 then -- Outland
|
||||
selectedContinentId = 3
|
||||
elseif currentContinentId == 571 then -- Northrend
|
||||
selectedContinentId = 4
|
||||
elseif l10n.zoneLookup[currentContinentId] then -- Dungeon
|
||||
selectedContinentId = 5
|
||||
end
|
||||
|
||||
if _QuestieJourney.lastZoneSelection[1] then
|
||||
selectedContinentId = _QuestieJourney.lastZoneSelection[1]
|
||||
end
|
||||
|
||||
dropdown:SetValue(selectedContinentId)
|
||||
return dropdown
|
||||
end
|
||||
|
||||
_CreateZoneDropdown = function()
|
||||
local dropdown = AceGUI:Create("Dropdown")
|
||||
|
||||
local currentZoneId = QuestiePlayer:GetCurrentZoneId()
|
||||
if _QuestieJourney.lastZoneSelection[2] then
|
||||
currentZoneId = _QuestieJourney.lastZoneSelection[2]
|
||||
end
|
||||
|
||||
local zones = QuestieJourney.zones[selectedContinentId]
|
||||
if currentZoneId and currentZoneId > 0 and zones then
|
||||
local sortedZones = QuestieJourneyUtils:GetSortedZoneKeys(zones)
|
||||
dropdown:SetList(zones, sortedZones)
|
||||
dropdown:SetValue(currentZoneId)
|
||||
|
||||
local zoneTree = _QuestieJourney.questsByZone:CollectZoneQuests(currentZoneId)
|
||||
_QuestieJourney.questsByZone:ManageTree(treegroup, zoneTree)
|
||||
elseif currentZoneId == RESET and zones then
|
||||
dropdown:SetText(l10n('Select Your Zone'))
|
||||
local sortedZones = QuestieJourneyUtils:GetSortedZoneKeys(zones)
|
||||
dropdown:SetList(zones, sortedZones)
|
||||
else
|
||||
dropdown:SetDisabled(true)
|
||||
end
|
||||
|
||||
dropdown:SetCallback("OnValueChanged", _HandleZoneSelection)
|
||||
return dropdown
|
||||
end
|
||||
|
||||
_HandleContinentSelection = function(key, _)
|
||||
if (key.value == QuestieJourney.questCategoryKeys.CLASS) then
|
||||
local _, class, _ = UnitClass("player")
|
||||
local classKey = QuestieDB:GetZoneOrSortForClass(class)
|
||||
local zoneTree = _QuestieJourney.questsByZone:CollectZoneQuests(classKey)
|
||||
_QuestieJourney.questsByZone:ManageTree(treegroup, zoneTree)
|
||||
zoneDropdown.frame:Hide()
|
||||
elseif (key.value == QuestieJourney.questCategoryKeys.PROFESSIONS) then
|
||||
local professionList = QuestieJourney.zones[key.value]
|
||||
local playerProfessions = QuestieProfessions:GetPlayerProfessionNames()
|
||||
|
||||
local relevantProfessions = {}
|
||||
for id, possibleName in pairs(professionList) do
|
||||
for _, name in pairs(playerProfessions) do
|
||||
if possibleName == name then
|
||||
relevantProfessions[id] = professionList[id]
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
local text = l10n('Select Your Profession')
|
||||
if (not next(relevantProfessions)) then
|
||||
text = l10n('No Quests found')
|
||||
zoneDropdown:SetDisabled(true)
|
||||
else
|
||||
zoneDropdown:SetDisabled(false)
|
||||
end
|
||||
zoneDropdown:SetList(relevantProfessions)
|
||||
zoneDropdown:SetText(text)
|
||||
zoneDropdown.frame:Show()
|
||||
else
|
||||
local sortedZones = QuestieJourneyUtils:GetSortedZoneKeys(QuestieJourney.zones[key.value])
|
||||
zoneDropdown:SetList(QuestieJourney.zones[key.value], sortedZones)
|
||||
zoneDropdown:SetText(l10n("Select Your Zone"))
|
||||
zoneDropdown:SetDisabled(false)
|
||||
zoneDropdown.frame:Show()
|
||||
end
|
||||
|
||||
_QuestieJourney.lastZoneSelection[2] = RESET
|
||||
_QuestieJourney.lastZoneSelection[1] = key.value
|
||||
end
|
||||
|
||||
_HandleZoneSelection = function(key, _)
|
||||
local zoneTree = _QuestieJourney.questsByZone:CollectZoneQuests(key.value)
|
||||
_QuestieJourney.questsByZone:ManageTree(treegroup, zoneTree)
|
||||
_QuestieJourney.lastZoneSelection[2] = key.value
|
||||
end
|
||||
Reference in New Issue
Block a user