Back to Home

ESO Lua File v100035

ingame/crafting/craftadvisor_manager.lua

[◄ back to folders ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
ZO_CraftAdvisorManager = ZO_CallbackObject:Subclass()
local DEFAULT_SELECTED_QUEST_INDEX = 1
function ZO_CraftAdvisorManager:New(...)
    local manager = ZO_CallbackObject.New(self)
    manager:Initialize(...)
    return manager
end
function ZO_CraftAdvisorManager:Initialize()
    self.craftingInteractionType = CRAFTING_TYPE_INVALID
    self.questMasterList = {}
    self.selectedMasterListIndex = DEFAULT_SELECTED_QUEST_INDEX
    EVENT_MANAGER:RegisterForEvent("ZO_CraftAdvisorManager", EVENT_CRAFTING_STATION_INTERACT, function(eventCode, craftingType, sameStation)
        --If we are at a different type of crafting station, we need to update the list
        --Otherwise, if anything has changed, we will have already attempted to refresh via the quest events
        --We also need to refresh if the player goes to a new smithing station, since they might be changing to a new set station
        if craftingType ~= self.craftingInteractionType or (not sameStation and IsSmithingCraftingType(craftingType)) then
            self.craftingInteractionType = craftingType
            self:RefreshQuestMasterList()
        end
    end)
    local function UpdateQuestConditions(questIndex, mainStepChanged)
        if mainStepChanged then
            self:RefreshQuestMasterList()
        end
        local currentlySelectedQuest = self.questMasterList[self.selectedMasterListIndex]
        if currentlySelectedQuest and currentlySelectedQuest.questIndex == questIndex then
            self:UpdateQuestConditionInfo()
            --Tell the craft advisor that it needs to refresh the quest display
            self:FireCallbacks("SelectedQuestConditionsUpdated")
        end
    end
    --Register for the various quest change events
    EVENT_MANAGER:RegisterForEvent("ZO_CraftAdvisorManager", EVENT_QUEST_CONDITION_COUNTER_CHANGED, function(_, questIndex) UpdateQuestConditions(questIndex) end)
    EVENT_MANAGER:RegisterForEvent("ZO_CraftAdvisorManager", EVENT_QUEST_ADVANCED, function(_, questIndex, questName, isPushed, isComplete, mainStepChanged) UpdateQuestConditions(questIndex, mainStepChanged) end)
    EVENT_MANAGER:RegisterForEvent("ZO_CraftAdvisorManager", EVENT_ACHIEVEMENT_UPDATED, function()
        --We need to register for this event to detect if a new translation has been discovered
        --Presumably, this can only happen while enchanting, so if the enchanting scene is not showing, we shouldn't care
        if ZO_Enchanting_IsSceneShowing() then
            self:UpdateQuestConditionInfo()
            self:FireCallbacks("SelectedQuestConditionsUpdated")
        end 
    end)
    --We need to rebuild when the inventory changes so we can make sure we display the proper messaging if there are missing materials/runes/reagents/etc
    EVENT_MANAGER:RegisterForEvent("ZO_CraftAdvisorManager", EVENT_INVENTORY_FULL_UPDATE, function() self:FireCallbacks("SelectedQuestConditionsUpdated") end)
    EVENT_MANAGER:RegisterForEvent("ZO_CraftAdvisorManager", EVENT_INVENTORY_SINGLE_SLOT_UPDATE, function() self:FireCallbacks("SelectedQuestConditionsUpdated") end)
    --We need to rebuild when we learn a new recipe so we can make sure we display the proper messaging for missing recipes
    EVENT_MANAGER:RegisterForEvent("ZO_CraftAdvisorManager", EVENT_RECIPE_LEARNED, function() self:FireCallbacks("SelectedQuestConditionsUpdated") end)
    EVENT_MANAGER:RegisterForEvent("ZO_CraftAdvisorManager", EVENT_MULTIPLE_RECIPES_LEARNED, function() self:FireCallbacks("SelectedQuestConditionsUpdated") end)
    --We need to rebuild if the player's solvent proficiency changed or they got the Laboratory Use skill, to ensure the error messaging refreshes
    EVENT_MANAGER:RegisterForEvent("ZO_CraftAdvisorManager", EVENT_NON_COMBAT_BONUS_CHANGED, function(eventCode, nonCombatBonusType)
        if nonCombatBonusType == NON_COMBAT_BONUS_ALCHEMY_THIRD_SLOT or nonCombatBonusType == NON_COMBAT_BONUS_ALCHEMY_LEVEL then
            self:FireCallbacks("SelectedQuestConditionsUpdated")
        end
    end)
    QUEST_JOURNAL_MANAGER:RegisterCallback("QuestListUpdated", function() self:RefreshQuestMasterList() end)
end
function ZO_CraftAdvisorManager:HasActiveWrits()
    return self.questMasterList and #self.questMasterList > 0
end
function ZO_CraftAdvisorManager:RefreshQuestMasterList()
    --Grab the current quest information from the journal
    local quests = QUEST_JOURNAL_MANAGER:GetQuestList()
    --Clear out the current quest pin data
    self:FireCallbacks("QuestInformationUpdated", {patternIndices = {}, materialIndex = nil, traitId = nil, styleId = nil, recipeItemIds = {}, runeIds = {}, alchemyInfo = {}, improvementInfo = {}})
    self.selectedMasterListIndex = DEFAULT_SELECTED_QUEST_INDEX 
    ZO_ClearTable(self.questMasterList)
    --Filter out any non-crafting quests from the list
    for i, questInfo in ipairs(quests) do
        if questInfo.questType == QUEST_TYPE_CRAFTING then
            local conditionCount = select(5, GetJournalQuestStepInfo(questInfo.questIndex, QUEST_MAIN_STEP_INDEX))
            local conditionInfo = {}
            for conditionIndex = 1, conditionCount do
                local conditionType = select(8, GetJournalQuestConditionInfo(questInfo.questIndex, QUEST_MAIN_STEP_INDEX, conditionIndex))
                if conditionType == QUEST_CONDITION_TYPE_GATHER_ITEM then
                    local itemId, materialItemId, craftingType, itemFunctionalQuality = GetQuestConditionItemInfo(questInfo.questIndex, QUEST_MAIN_STEP_INDEX, conditionIndex)
                    --If any of the condition crafting types match the current interaction type, we want to include this quest
                    local shouldShowQuest = (craftingType == self.craftingInteractionType)
                    --Provisioning is special in that in can be done at any crafting station type, so we need to do a slightly different check for it
                    if craftingType == CRAFTING_TYPE_PROVISIONING then
                        local craftingStationType = GetRecipeInfoFromItemId(itemId)
                        shouldShowQuest = (craftingStationType == self.craftingInteractionType)
                    end
                    if shouldShowQuest then
                        local data = 
                        {
                            conditionIndex = conditionIndex,
                            itemId = itemId,
                            materialItemId = materialItemId,
                            craftingType = craftingType,
                            itemFunctionalQuality = itemFunctionalQuality,
                            isMasterWrit = false,
                        }
                        table.insert(conditionInfo, data)
                    end
                elseif conditionType == QUEST_CONDITION_TYPE_CRAFT_RANDOM_WRIT_ITEM then
                    local itemId, materialItemId, craftingType, itemFunctionalQuality, itemTemplateId, itemSetId, itemTraitType, itemStyleId, encodedAlchemyTraits = GetQuestConditionMasterWritInfo(questInfo.questIndex, QUEST_MAIN_STEP_INDEX, conditionIndex)
                    --If any of the condition crafting types match the current interaction type, we want to include this quest
                    local shouldShowQuest = (craftingType == self.craftingInteractionType)
                    --Provisioning is special in that in can be done at any crafting station type, so we need to do a slightly different check for it
                    if craftingType == CRAFTING_TYPE_PROVISIONING then
                        local craftingStationType = GetRecipeInfoFromItemId(itemId)
                        shouldShowQuest = (craftingStationType == self.craftingInteractionType)
                    end
                    if shouldShowQuest then
                        local data = 
                        {
                            conditionIndex = conditionIndex,
                            itemId = itemId,
                            materialItemId = materialItemId,
                            craftingType = craftingType,
                            itemFunctionalQuality = itemFunctionalQuality,
                            itemTemplateId = itemTemplateId,
                            itemSetId = itemSetId,
                            itemTraitType = itemTraitType,
                            itemStyleId = itemStyleId,
                            encodedAlchemyTraits = encodedAlchemyTraits,
                            isMasterWrit = true,
                        }
                        --Smithing master writs should only show up at their specific set station
                        if IsSmithingCraftingType(craftingType) then
                            if CanSpecificSmithingItemSetPatternBeCraftedHere(itemSetId) then
                                table.insert(conditionInfo, data)
                            end
                        else
                            table.insert(conditionInfo, data)
                        end
                    end
                end
            end
            if #conditionInfo > 0 then
                questInfo.conditionData = conditionInfo
                table.insert(self.questMasterList, questInfo)
            end
        end
    end
    self:FireCallbacks("QuestMasterListUpdated", self.questMasterList)
end
function ZO_CraftAdvisorManager:GetMissingMessage(conditionInfo, currentCount, maxCount)
    --If we have already met the condition requirements, we no longer care about what components we have
    if currentCount < maxCount then
        if conditionInfo.craftingType == CRAFTING_TYPE_ENCHANTING then
            local potencyRune, essenceRune, aspectRune = GetRunesForItemIdIfKnown(conditionInfo.itemId, conditionInfo.materialItemId, conditionInfo.itemFunctionalQuality)
            --GetRunesForItemIdIfKnown will return nil for all values if any of the runes are unknown
            --Therefore, checking any of them for nil would be sufficient, it doesn't have to be potency
            if potencyRune == nil then
                return GetString(SI_ENCHANTING_UNKNOWN_RUNES), GetString(SI_CRAFT_ADVISOR_UNKNOWN_RUNES_TOOLTIP)
            elseif not DoesPlayerHaveRunesForEnchanting(aspectRune, essenceRune, potencyRune) then
                return GetString(SI_CRAFTING_MISSING_ITEMS), GetString(SI_CRAFT_ADVISOR_ENCHANTING_MISSING_ITEMS_TOOLTIP)
            end
        elseif conditionInfo.craftingType == CRAFTING_TYPE_PROVISIONING then
            local recipeLists = PROVISIONER_MANAGER:GetRecipeListData(self.craftingInteractionType)
            --Look for a matching recipe
            for listIndex, recipeList in pairs(recipeLists) do
                for _, recipe in ipairs(recipeList.recipes) do
                    --If we have a match, then we're done, return early
                    if recipe.resultItemId == conditionInfo.itemId then
                        return
                    end
                end
            end
            --If we get here, that means we are missing the recipe
            return GetString(SI_PROVISIONER_MISSING_RECIPE), GetString(SI_CRAFT_ADVISOR_PROVISIONING_MISSING_RECIPE_TOOLTIP)
        elseif conditionInfo.craftingType == CRAFTING_TYPE_ALCHEMY then
            local validCombinationFound = false
            local needsThirdSlot = conditionInfo.isMasterWrit and GetNonCombatBonus(NON_COMBAT_BONUS_ALCHEMY_THIRD_SLOT) == 0
            --Check and see if the alchemy logic has found any valid combinations
            if IsInGamepadPreferredMode() then   
                validCombinationFound = GAMEPAD_ALCHEMY:HasValidCombinationForQuest()
            else
                validCombinationFound = ALCHEMY:HasValidCombinationForQuest()
            end
            if needsThirdSlot then
                return GetString(SI_ALCHEMY_REQUIRES_THIRD_SLOT), GetString(SI_CRAFT_ADVISOR_ALCHEMY_REQUIRES_THIRD_SLOT_TOOLTIP)
            elseif not validCombinationFound then
                return GetString(SI_ALCHEMY_MISSING_OR_UNKNOWN), GetString(SI_CRAFT_ADVISOR_ALCHEMY_MISSING_OR_UNKNOWN_TOOLTIP)
            end
        end
    end
end
function ZO_CraftAdvisorManager:UpdateQuestConditionInfo()
    local questInfo = self.questMasterList[self.selectedMasterListIndex]
    local craftingQuestIndices = 
    {
        patternIndices = {},
        materialIndex = nil,
        traitId = nil,
        styleId = nil,
        recipeItemIds = {},
        runeIds = {},
        alchemyInfo = {},
        improvementInfo = {},
    }
    if questInfo then
        --Determine the pattern and material information for each relevant condition
        for _, conditionInfo in ipairs(questInfo.conditionData) do
            if IsSmithingCraftingType(conditionInfo.craftingType) then
                local _, curCount, maxCount = GetJournalQuestConditionInfo(questInfo.questIndex, QUEST_MAIN_STEP_INDEX, conditionInfo.conditionIndex)
                --If this is a master writ, we need different information from normal ones
                if conditionInfo.isMasterWrit then
                    local patternIndex, materialIndex, desiredItemId = GetSmithingPatternInfoForItemSet(conditionInfo.itemTemplateId, conditionInfo.itemSetId, conditionInfo.materialItemId, conditionInfo.itemTraitType)
                    if patternIndex and materialIndex and curCount < maxCount then
                        craftingQuestIndices.patternIndices[patternIndex] = true
                        craftingQuestIndices.materialIndex = materialIndex
                        craftingQuestIndices.traitId = conditionInfo.itemTraitType
                        craftingQuestIndices.styleId = conditionInfo.itemStyleId
                        craftingQuestIndices.hasPatterns = true
                        if desiredItemId and conditionInfo.itemFunctionalQuality and conditionInfo.materialItemId and conditionInfo.itemTraitType and conditionInfo.itemStyleId then
                            craftingQuestIndices.improvementInfo =
                            {
                                desiredItemId = desiredItemId,
                                desiredQuality = conditionInfo.itemFunctionalQuality,
                                desiredMaterial = conditionInfo.materialItemId,
                                desiredTrait = conditionInfo.itemTraitType,
                                desiredStyle = conditionInfo.itemStyleId,
                            }
                            craftingQuestIndices.hasItemToImproveForWrit = HasItemToImproveForWrit(desiredItemId, conditionInfo.materialItemId, conditionInfo.itemTraitType, conditionInfo.itemStyleId, conditionInfo.itemFunctionalQuality)
                        end
                    end
                else
                    local patternIndex, materialIndex = GetSmithingPatternInfoForItemId(conditionInfo.itemId, conditionInfo.materialItemId, conditionInfo.craftingType)
                    if patternIndex and materialIndex and curCount < maxCount then
                        craftingQuestIndices.patternIndices[patternIndex] = true
                        craftingQuestIndices.materialIndex = materialIndex
                        craftingQuestIndices.hasPatterns = true
                    elseif curCount < maxCount then
                        craftingQuestIndices.smithingItemId = conditionInfo.itemId
                    end
                end
            elseif conditionInfo.craftingType == CRAFTING_TYPE_PROVISIONING then
                local _, curCount, maxCount = GetJournalQuestConditionInfo(questInfo.questIndex, QUEST_MAIN_STEP_INDEX, conditionInfo.conditionIndex)
                if curCount < maxCount then
                    craftingQuestIndices.recipeItemIds[conditionInfo.itemId] = true
                    craftingQuestIndices.hasRecipesForQuest = true
                end
            elseif conditionInfo.craftingType == CRAFTING_TYPE_ENCHANTING then
                local _, curCount, maxCount = GetJournalQuestConditionInfo(questInfo.questIndex, QUEST_MAIN_STEP_INDEX, conditionInfo.conditionIndex)
                local potencyRune, essenceRune, aspectRune = GetRunesForItemIdIfKnown(conditionInfo.itemId, conditionInfo.materialItemId, conditionInfo.itemFunctionalQuality)
                if potencyRune and essenceRune and aspectRune and curCount < maxCount then
                    craftingQuestIndices.runeIds = 
                    {
                        potency = potencyRune,
                        essence = essenceRune,
                        aspect = aspectRune
                    }
                else
                    craftingQuestIndices.runeIds = 
                    {
                        hasRequiredGlyph = curCount >= maxCount
                    }
                end
            elseif conditionInfo.craftingType == CRAFTING_TYPE_ALCHEMY then
                local _, curCount, maxCount = GetJournalQuestConditionInfo(questInfo.questIndex, QUEST_MAIN_STEP_INDEX, conditionInfo.conditionIndex)
                --If this is a master writ, we need different alchemy information than for normal writs
                if conditionInfo.isMasterWrit then
                    if conditionInfo.encodedAlchemyTraits and curCount < maxCount then
                        craftingQuestIndices.alchemyInfo =
                        {
                            basePotionItemId = conditionInfo.itemId,
                            materialItemId = conditionInfo.materialItemId,
                            encodedTraits = conditionInfo.encodedAlchemyTraits,
                            isMasterWrit = true
                        }
                    else
                        craftingQuestIndices.alchemyInfo =
                        {
                            hasDesiredPotion = curCount >= maxCount
                        }
                    end
                else
                    local desiredTraitId = GetTraitIdFromBasePotion(conditionInfo.itemId)
                    if desiredTraitId ~= 0 and curCount < maxCount then
                        craftingQuestIndices.alchemyInfo =
                        {
                            basePotionItemId = conditionInfo.itemId,
                            materialItemId = conditionInfo.materialItemId,
                            desiredTrait = desiredTraitId
                        }
                    else
                        craftingQuestIndices.alchemyInfo =
                        {
                            hasDesiredPotion = curCount >= maxCount
                        }
                    end
                end
            end
        end
    end
    --Send out the updated data necessary for the quest pins
    self:FireCallbacks("QuestInformationUpdated", craftingQuestIndices)
end
function ZO_CraftAdvisorManager:OnSelectionChanged(questIndex)
    for i, questInfo in ipairs(self.questMasterList) do
        --Locate the newly selected quest
        if questInfo.questIndex == questIndex then
            self.selectedMasterListIndex = i
            self:UpdateQuestConditionInfo()
            return
        end
    end
end
function ZO_CraftAdvisorManager:ShouldDeferRefresh()
    return self.craftingInteractionType == CRAFTING_TYPE_ALCHEMY
end
CRAFT_ADVISOR_MANAGER = ZO_CraftAdvisorManager:New()