diff --git a/esoui/ingame/collections/keyboard/collectionsbook.lua b/esoui/ingame/collections/keyboard/collectionsbook.lua
index 89304d6..1a28edf 100755
--- a/esoui/ingame/collections/keyboard/collectionsbook.lua
+++ b/esoui/ingame/collections/keyboard/collectionsbook.lua
@@ -8,6 +8,8 @@ local COLLECTIBLE_STICKER_ROW_STRIDE = 3
local MAX_COLLECTIBLE_ROW_WIDTH = (COLLECTIBLE_STICKER_SINGLE_WIDTH + COLLECTIBLE_PADDING) * COLLECTIBLE_STICKER_ROW_STRIDE
local RETAIN_SCROLL_POSITION = true
local DONT_RETAIN_SCROLL_POSITION = true
+local ACTIVE_ICON = "EsoUI/Art/Inventory/inventory_icon_equipped.dds"
+local NOTIFICATIONS_PROVIDER = NOTIFICATIONS:GetCollectionsProvider()
--Descriptive defaults for readibility in function calls
local FORCE_HIDE_PROGRESS_TEXT = true
@@ -45,10 +47,19 @@ function Collectible:Initialize(control, gridDimensions)
self.title = control:GetNamedChild("Title")
self.highlight = control:GetNamedChild("Highlight")
self.icon = control:GetNamedChild("Icon")
- self.activeIcon = control:GetNamedChild("ActiveIcon")
+ self.multiIcon = control:GetNamedChild("MultiIcon")
self.cornerTag = control:GetNamedChild("CornerTag")
+ self.cooldownIcon = control:GetNamedChild("CooldownIcon")
+ self.cooldownIconDesaturated = control:GetNamedChild("CooldownIconDesaturated")
+ self.cooldownTime = control:GetNamedChild("CooldownTime")
+ self.cooldownEdge = control:GetNamedChild("CooldownEdge")
+ self.isCooldownActive = false
+ self.maxIconHeight = self.icon:GetHeight()
+
self.iconAnimation = ANIMATION_MANAGER:CreateTimelineFromVirtual("JournalProgressIconSlotMouseOverAnimation", self.icon)
+
+ COLLECTIONS_BOOK_SINGLETON:RegisterCallback("OnUpdateCooldowns", function(...) self:OnUpdateCooldowns(...) end)
end
function Collectible:Show(collectibleId, previousControl)
@@ -59,9 +70,16 @@ function Collectible:Show(collectibleId, previousControl)
self.unlocked = unlocked
self.purchasable = purchasable
self.title:SetText(zo_strformat(SI_COLLECTIBLE_NAME_FORMATTER, name))
- self.icon:SetTexture(effectiveIcon or ZO_NO_TEXTURE_FILE)
+ self.icon:SetTexture(effectiveIcon)
ApplyTextColorToLabel(self.title, unlocked, ZO_NORMAL_TEXT, ZO_DISABLED_TEXT)
+ self.cooldownIcon:SetTexture(effectiveIcon)
+ self.cooldownIconDesaturated:SetTexture(effectiveIcon)
+ self.cooldownIconDesaturated:SetDesaturation(1)
+ self.cooldownTime:SetText("")
+ self.cooldownDuration = 0
+ self.cooldownStartTime = 0
+
self.title:SetHidden(false)
self.icon:SetHidden(false)
self:SetAnchor(previousControl)
@@ -70,14 +88,31 @@ function Collectible:Show(collectibleId, previousControl)
self.categoryType = categoryType
self.active = isActive
- self.activeIcon:SetHidden(not isActive)
+ self:RefreshMultiIcon()
+ self:SetBlockedState(IsCollectibleCategoryBlocked(categoryType))
- self.isUsable = unlocked and COLLECTIONS_INVENTORY_VALID_CATEGORY_TYPES[categoryType] and
- not (isActive and categoryType == COLLECTIBLE_CATEGORY_TYPE_MOUNT) --a mount must always be set
+ self.isUsable = IsCollectibleUsable(collectibleId)
if self.isCurrentMouseTarget then
self:ShowKeybinds()
end
+
+ self:OnUpdateCooldowns()
+end
+
+function Collectible:RefreshMultiIcon()
+ self.multiIcon:ClearIcons()
+
+ if self.active then
+ self.multiIcon:AddIcon(ACTIVE_ICON)
+ end
+
+ self.notificationId = NOTIFICATIONS_PROVIDER:GetNotificationIdForCollectible(self.collectibleId)
+ if self.notificationId then
+ self.multiIcon:AddIcon(ZO_KEYBOARD_NEW_ICON)
+ end
+
+ self.multiIcon:Show()
end
function Collectible:ShowBlank(previousControl)
@@ -87,8 +122,11 @@ function Collectible:ShowBlank(previousControl)
self.icon:SetHidden(true)
self:SetAnchor(previousControl)
self.control:SetHidden(false)
- self.activeIcon:SetHidden(true)
+ self.multiIcon:ClearIcons()
self.cornerTag:SetHidden(true)
+ if self.isCooldownActive then
+ self:EndCooldown()
+ end
end
function Collectible:GetId()
@@ -127,7 +165,6 @@ end
function Collectible:Reset()
self.control:SetHidden(true)
- self:SetHighlightHidden(true)
end
function Collectible:SetHighlightHidden(hidden)
@@ -142,9 +179,29 @@ function Collectible:SetHighlightHidden(hidden)
self.highlightAnimation:PlayBackward()
else
ApplyTextColorToLabel(self.title, self.unlocked, ZO_HIGHLIGHT_TEXT, ZO_SELECTED_TEXT)
- self.iconAnimation:PlayForward()
self.highlightAnimation:PlayForward()
+ if self.isCooldownActive ~= true then
+ self.iconAnimation:PlayForward()
+ end
+ end
+end
+
+function Collectible:GetInteractionTextEnum()
+ local textEnum
+ if self.isCooldownActive ~= true and self.isBlocked ~= true then
+ if self.categoryType == COLLECTIBLE_CATEGORY_TYPE_TROPHY then
+ textEnum = SI_COLLECTIBLE_ACTION_USE
+ elseif self.active then
+ if self.categoryType == COLLECTIBLE_CATEGORY_TYPE_VANITY_PET or self.categoryType == COLLECTIBLE_CATEGORY_TYPE_ASSISTANT then
+ textEnum = SI_COLLECTIBLE_ACTION_DISMISS
+ else
+ textEnum = SI_COLLECTIBLE_ACTION_PUT_AWAY
+ end
+ else
+ textEnum = SI_COLLECTIBLE_ACTION_SET_ACTIVE
+ end
end
+ return textEnum
end
function Collectible:ShowCollectibleMenu()
@@ -157,9 +214,11 @@ function Collectible:ShowCollectibleMenu()
--Use
if self.isUsable then
- local textEnum = self.active and SI_COLLECTIBLE_ACTION_PUT_AWAY or SI_COLLECTIBLE_ACTION_SET_ACTIVE
+ local textEnum = self:GetInteractionTextEnum()
+ if textEnum then
AddMenuItem(GetString(textEnum), function() UseCollectible(collectibleId) end)
end
+ end
if IsChatSystemAvailableForCurrentPlatform() then
--Link in chat
@@ -197,12 +256,13 @@ function Collectible:ShowKeybinds()
end
if self.isUsable then
- local textEnum = self.active and SI_COLLECTIBLE_ACTION_PUT_AWAY or SI_COLLECTIBLE_ACTION_SET_ACTIVE
+ local textEnum = self:GetInteractionTextEnum()
+ if textEnum then
g_keybindUseCollectible.name = GetString(textEnum)
g_keybindUseCollectible.callback = function() UseCollectible(self.collectibleId) end
-
UpdateKeybind(g_keybindUseCollectible)
end
+ end
if IsCollectibleRenameable(self.collectibleId) then
g_keybindRenameCollectible.callback = function() ZO_Dialogs_ShowDialog("COLLECTIONS_INVENTORY_RENAME_COLLECTIBLE", { collectibleId = self.collectibleId }) end
@@ -238,6 +298,10 @@ function Collectible:OnMouseExit()
if self.purchasable then
self.cornerTag:SetHidden(true)
end
+
+ if self.notificationId then
+ RemoveCollectibleNotification(self.notificationId)
+ end
end
end
@@ -260,6 +324,73 @@ function Collectible:OnEffectivelyHidden()
self:HideKeybinds()
end
+function Collectible:OnUpdate()
+ if self.isUsable and self.isCooldownActive then
+ self:UpdateCooldownEffect()
+ end
+end
+
+function Collectible:OnUpdateCooldowns()
+ if self.isUsable then
+ local remaining, duration = GetCollectibleCooldownAndDuration(self.collectibleId)
+ if remaining > 0 and duration > 0 then
+ if self.isCooldownActive == false then
+ self.cooldownDuration = duration
+ self.cooldownStartTime = GetFrameTimeMilliseconds() - (duration - remaining)
+ self:BeginCooldown()
+ end
+ elseif self.isCooldownActive == true then
+ self:EndCooldown()
+ end
+ elseif self.isCooldownActive == true then
+ self:EndCooldown()
+ end
+end
+
+function Collectible:BeginCooldown()
+ self.isCooldownActive = true
+ self.cooldownIcon:SetHidden(false)
+ self.cooldownIconDesaturated:SetHidden(false)
+ self.cooldownTime:SetHidden(false)
+ self.cooldownEdge:SetHidden(false)
+ self:SetHighlightHidden(true)
+ self:HideKeybinds()
+end
+
+function Collectible:EndCooldown()
+ self.isCooldownActive = false
+ self.cooldownIcon:SetTextureCoords(0, 1, 0, 1)
+ self.cooldownIcon:SetHeight(self.maxIconHeight)
+ self.cooldownIcon:SetHidden(true)
+ self.cooldownIconDesaturated:SetHidden(true)
+ self.cooldownTime:SetHidden(true)
+ self.cooldownEdge:SetHidden(true)
+ self.cooldownTime:SetText("")
+ self:ShowKeybinds()
+ if self.isCurrentMouseTarget then
+ self:SetHighlightHidden(false)
+ end
+end
+
+function Collectible:UpdateCooldownEffect()
+ local duration = self.cooldownDuration
+ local cooldown = self.cooldownStartTime + duration - GetFrameTimeMilliseconds()
+ local percentCompleted = (1 - (cooldown / duration)) or 1
+ local height = zo_ceil(self.maxIconHeight * percentCompleted)
+ local textureCoord = 1 - (height / self.maxIconHeight)
+
+ self.cooldownTime:SetText(ZO_FormatTimeMilliseconds(cooldown, TIME_FORMAT_STYLE_DESCRIPTIVE_SHORT_SHOW_ZERO_SECS))
+ self.cooldownIcon:SetHeight(height)
+ self.cooldownIcon:SetTextureCoords(0, 1, textureCoord, 1)
+end
+
+function Collectible:SetBlockedState(isBlocked)
+ local desaturation = isBlocked and 1 or 0
+ self.icon:SetDesaturation(desaturation)
+ self.highlight:SetDesaturation(desaturation)
+ self.isBlocked = isBlocked
+end
+
--[[ Collection ]]--
--------------------
--[[ Initialization ]]--
@@ -346,6 +477,7 @@ function CollectionsBook:InitializeEvents()
COLLECTIONS_BOOK_SINGLETON:RegisterCallback("OnCollectibleUpdated", function(...) self:OnCollectibleUpdated(...) end)
COLLECTIONS_BOOK_SINGLETON:RegisterCallback("OnCollectionUpdated", function(...) self:OnCollectionUpdated(...) end)
+ COLLECTIONS_BOOK_SINGLETON:RegisterCallback("OnCollectionNotificationRemoved", function(...) self:OnCollectionNotificationRemoved(...) end)
self.refreshGroups = ZO_Refresh:New()
self.refreshGroups:AddRefreshGroup("FullUpdate",
@@ -363,6 +495,12 @@ function CollectionsBook:InitializeEvents()
})
end
+function CollectionsBook:InitializeCategoryTemplates()
+ self.parentCategoryTemplate = "ZO_CollectibleIconHeader"
+ self.childlessCategoryTemplate = "ZO_CollectibleChildlessCategory"
+ self.subCategoryTemplate = "ZO_CollectibleSubCategory"
+end
+
function CollectionsBook:InitializeSummary(control)
ZO_JournalProgressBook_Common.InitializeSummary(self, control, GetString(SI_COLLECTIONS_BOOK_OVERALL))
end
@@ -436,52 +574,95 @@ function CollectionsBook:BuildCategories()
self.categoryTree:Reset()
self.nodeLookupData = {}
+ local function AddCategoryByCategoryIndex(categoryIndex)
+ local name, numSubCategories, _, _, _, hidesUnearned, categoryType = self:GetCategoryInfo(categoryIndex)
+ --DLC is handled by the DLC book now
+ if categoryType ~= COLLECTIBLE_CATEGORY_TYPE_DLC then
+ local normalIcon, pressedIcon, mouseoverIcon = self:GetCategoryIcons(categoryIndex)
+ self:AddTopLevelCategory(categoryIndex, zo_strformat(SI_COLLECTIBLE_NAME_FORMATTER, name), numSubCategories, hidesUnearned, normalIcon, pressedIcon, mouseoverIcon)
+ end
+ end
+
if self.searchString == "" then
- for i = 1, self:GetNumCategories() do
- local name, numSubCategories, _, _, _, hidesUnearned = self:GetCategoryInfo(i)
- local normalIcon, pressedIcon, mouseoverIcon = self:GetCategoryIcons(i)
- self:AddTopLevelCategory(i, zo_strformat(SI_COLLECTIBLE_NAME_FORMATTER, name), numSubCategories, hidesUnearned, normalIcon, pressedIcon, mouseoverIcon)
+ for categoryIndex = 1, self:GetNumCategories() do
+ AddCategoryByCategoryIndex(categoryIndex)
end
else
for categoryIndex, data in pairs(self.searchResults) do
- local name, numSubCategories, _, _, _, hidesUnearned = self:GetCategoryInfo(categoryIndex)
- local normalIcon, pressedIcon, mouseoverIcon = self:GetCategoryIcons(categoryIndex)
- self:AddTopLevelCategory(categoryIndex, zo_strformat(SI_COLLECTIBLE_NAME_FORMATTER, name), numSubCategories, hidesUnearned, normalIcon, pressedIcon, mouseoverIcon)
+ AddCategoryByCategoryIndex(categoryIndex)
end
end
self.categoryTree:Commit()
+
+ self:UpdateAllCategoryStatuses()
end
function CollectionsBook:AddTopLevelCategory(categoryIndex, name, numSubCategories, hidesUnearned, normalIcon, pressedIcon, mouseoverIcon)
+ local parent
if self.searchString == "" then
- ZO_JournalProgressBook_Common.AddTopLevelCategory(self, categoryIndex, name, numSubCategories, hidesUnearned, normalIcon, pressedIcon, mouseoverIcon)
+ parent = ZO_JournalProgressBook_Common.AddTopLevelCategory(self, categoryIndex, name, numSubCategories, hidesUnearned, normalIcon, pressedIcon, mouseoverIcon)
else
--Special search layout
local tree = self.categoryTree
local lookup = self.nodeLookupData
local hasChildren = NonContiguousCount(self.searchResults[categoryIndex]) > 1 or self.searchResults[categoryIndex]["root"] == nil
- local nodeTemplate = hasChildren and "ZO_IconHeader" or "ZO_JournalChildlessCategory"
+ local nodeTemplate = hasChildren and self.parentCategoryTemplate or self.childlessCategoryTemplate
- local parent = self:AddCategory(lookup, tree, nodeTemplate, nil, categoryIndex, name, hidesUnearned, normalIcon, pressedIcon, mouseoverIcon)
+ parent = self:AddCategory(lookup, tree, nodeTemplate, nil, categoryIndex, name, hidesUnearned, normalIcon, pressedIcon, mouseoverIcon)
--We only want to add a general subcategory if we have any subcategories and we have any collectibles in the main category
--Otherwise we'd have an emtpy general category, or only a general subcategory which can just be a childless instead
if(hasChildren and self.searchResults[categoryIndex]["root"]) then
local isFakedSubcategory = true
local isSummary = false
- self:AddCategory(lookup, tree, "ZO_JournalSubCategory", parent, categoryIndex, GetString(SI_JOURNAL_PROGRESS_CATEGORY_GENERAL), hidesUnearned, normalIcon, pressedIcon, mouseoverIcon, isSummary, isFakedSubcategory)
+ self:AddCategory(lookup, tree, self.subCategoryTemplate, parent, categoryIndex, GetString(SI_JOURNAL_PROGRESS_CATEGORY_GENERAL), hidesUnearned, normalIcon, pressedIcon, mouseoverIcon, isSummary, isFakedSubcategory)
end
for subcategoryIndex, data in pairs(self.searchResults[categoryIndex]) do
if subcategoryIndex ~= "root" then
local subCategoryName, subCategoryEntries, _, _, hidesUnearned = self:GetSubCategoryInfo(categoryIndex, subcategoryIndex)
- self:AddCategory(lookup, tree, "ZO_JournalSubCategory", parent, subcategoryIndex, zo_strformat(SI_COLLECTIBLE_NAME_FORMATTER, subCategoryName), nil, normalIcon, pressedIcon, mouseoverIcon)
+ self:AddCategory(lookup, tree, self.subCategoryTemplate, parent, subcategoryIndex, zo_strformat(SI_COLLECTIBLE_NAME_FORMATTER, subCategoryName), nil, normalIcon, pressedIcon, mouseoverIcon)
+ end
end
end
return parent
end
+
+function CollectionsBook:UpdateCategoryStatus(categoryNode)
+ local categoryData = categoryNode.data
+ local categoryControl = categoryNode.control
+
+ local categoryIndex
+ local subcategoryIndex
+ if categoryData.parentData then
+ categoryIndex = categoryData.parentData.categoryIndex
+ subcategoryIndex = categoryData.isFakedSubcategory and ZO_JOURNAL_PROGRESS_FAKED_SUBCATEGORY_INDEX or categoryData.categoryIndex
+ self:UpdateCategoryStatus(categoryData.parentData.node)
+ else
+ categoryIndex = categoryData.categoryIndex
+ end
+
+ if not categoryControl.statusIcon then
+ categoryControl.statusIcon = categoryControl:GetNamedChild("StatusIcon")
+ end
+
+ local showNewStatus = self:HasAnyNotifications(categoryIndex, subcategoryIndex)
+ categoryControl.statusIcon:SetHidden(not showNewStatus)
+end
+
+function CollectionsBook:UpdateAllCategoryStatuses()
+ for _, lookupData in pairs(self.nodeLookupData) do
+ local categoryNode = lookupData.node
+ if NonContiguousCount(lookupData.subCategories) == 0 then
+ self:UpdateCategoryStatus(categoryNode)
+ else
+ for _, subcategoryNode in pairs(lookupData.subCategories) do
+ self:UpdateCategoryStatus(subcategoryNode)
+ end
+ end
+ end
end
function CollectionsBook:UpdateCategoryLabels(data, retainScrollPosition)
@@ -611,15 +792,19 @@ end
function CollectionsBook:OnCollectibleUpdated(collectibleId)
self.refreshGroups:RefreshSingle("CollectibleUpdated", collectibleId)
+ MAIN_MENU_KEYBOARD:RefreshCategoryBar()
+ MAIN_MENU_KEYBOARD:UpdateSceneGroupButtons("collectionsSceneGroup")
end
function CollectionsBook:UpdateCollectible(collectibleId)
- if self:IsSummaryOpen() then
- self:UpdateSummary()
- else
local category, subcategory = GetCategoryInfoFromCollectibleId(collectibleId)
local categoryNode = self:GetLookupNodeByCategory(category, subcategory)
if categoryNode then
+ self:UpdateCategoryStatus(categoryNode)
+
+ if self:IsSummaryOpen() then
+ self:UpdateSummary()
+ else
local data = self.categoryTree:GetSelectedData()
if data.node == categoryNode then
self:UpdateCategoryLabels(data, RETAIN_SCROLL_POSITION)
@@ -628,9 +813,18 @@ function CollectionsBook:UpdateCollectible(collectibleId)
end
end
+function CollectionsBook:OnCollectionNotificationRemoved(notificationId, collectibleId)
+ self.refreshGroups:RefreshSingle("CollectibleUpdated", collectibleId)
+ MAIN_MENU_KEYBOARD:RefreshCategoryBar()
+ MAIN_MENU_KEYBOARD:UpdateSceneGroupButtons("collectionsSceneGroup")
+end
+
function CollectionsBook:BrowseToCollectible(collectibleId, categoryIndex, subcategoryIndex)
self.refreshGroups:UpdateRefreshGroups() --In case we need to rebuild the categories before we select a category
+ if DLC_BOOK_KEYBOARD:IsCategoryIndexDLC(categoryIndex) then
+ DLC_BOOK_KEYBOARD:BrowseToCollectible(collectibleId)
+ else
--Select the category or subcategory of the collectible
local categoryNode = self:GetLookupNodeByCategory(categoryIndex, subcategoryIndex)
if categoryNode then
@@ -641,6 +835,7 @@ function CollectionsBook:BrowseToCollectible(collectibleId, categoryIndex, subca
SCENE_MANAGER:Show("collectionsBook")
end
+end
--[[Search]]--
--------------
@@ -649,6 +844,14 @@ function CollectionsBook:SearchStart(searchString)
StartCollectibleSearch(searchString)
end
+function CollectionsBook:HasAnyNotifications(optionalCategoryIndexFilter, optionalSubcategoryIndexFilter)
+ return NOTIFICATIONS_PROVIDER:HasAnyNotifications(optionalCategoryIndexFilter, optionalSubcategoryIndexFilter)
+end
+
+function CollectionsBook:GetNotificationIdForCollectible(collectibleId)
+ return NOTIFICATIONS_PROVIDER:GetNotificationIdForCollectible(collectibleId)
+end
+
--[[Global functions]]--
------------------------
function ZO_CollectionsBook_OnInitialize(control)