diff --git a/Deprecation.lua b/Deprecation.lua
new file mode 100644
index 0000000..00b6418
--- /dev/null
+++ b/Deprecation.lua
@@ -0,0 +1,270 @@
+
+local function GetNextBookIndex(bookIndexes)
+ if bookIndexes.bookIndex >= bookIndexes.totalBooks then
+ if bookIndexes.collectionIndex >= bookIndexes.numCollections then
+ if bookIndexes.categoryIndex >= GetNumLoreCategories() then
+ return false
+ else
+ bookIndexes.categoryIndex = bookIndexes.categoryIndex + 1
+ bookIndexes.numCollections = select(2, GetLoreCategoryInfo(bookIndexes.categoryIndex))
+ bookIndexes.collectionIndex = 0
+ end
+ end
+ bookIndexes.collectionIndex = bookIndexes.collectionIndex + 1
+ bookIndexes.totalBooks = select(4, GetLoreCollectionInfo(bookIndexes.categoryIndex, bookIndexes.collectionIndex))
+ bookIndexes.bookIndex = 0
+ end
+ bookIndexes.bookIndex = bookIndexes.bookIndex + 1
+ return true
+end
+
+function Librarian:GetBookIdWithTitle(title)
+ -- list of book that aren't part of the eidetic memory
+ if title == "Adventurers Wanted!" then
+ return 4552
+ elseif title == "Behold Khunzar-ri's Ambition" then
+ return 5925
+ elseif title == "Behold Khunzar-ri's Betrayal" then
+ return 5673
+ elseif title == "Behold Khunzar-ri's Guile" then
+ return 5724
+ elseif title == "Behold the Lunar Champion" then
+ return 5669
+ elseif title == "Beldorr's Note" then
+ return 2933
+ elseif title == "Bounty: Dragons!" then
+ return 5708
+ elseif title == "Cadwell's Personal Anthem" then
+ return 2517
+ elseif title == "Crumpled Note" then
+ return 2925
+ elseif title == "Crumpled Nursery Rhyme" then
+ return 5460
+ elseif title == "Details on the Midyear Mayhem" then
+ return 4591
+ elseif title == "Diviner's Journal" then
+ return 4048
+ elseif title == "Engraved Pedestal" then
+ return 4006
+ elseif title == "Excavation Orders" then
+ return 4047
+ elseif title == "Falsehoods and Fallacies of the Eight" then
+ return 1279
+ elseif title == "Firuth's Writ" then
+ return 4042
+ elseif title == "From the Exalted Viper" then -- real name is "From the Regent of Fanged Fury"
+ return 2644
+ elseif title == "The Ghostly Stag" then
+ return 138
+ elseif title == "Guardian's Decree" then
+ return 4050
+ elseif title == "The Indrik's Glade" then
+ return 5027
+ elseif title == "Journal of the King's Seneschal" then
+ return 2015
+ elseif title == "Journal of Ulrich" then
+ return 132
+ elseif title == "Journal's Final Pages" then
+ return 2942
+ elseif title == "Jubilee Cake Voucher" then
+ return 6215
+ elseif title == "Keeper's Letter" then
+ return 4851
+ elseif title == "Khasaad's Treasure Map" then
+ return 727
+ elseif title == "Laughing Moons Ledger" then
+ return 1566
+ elseif title == "Legend of Shalug the Shark" then
+ return 3285
+ elseif title == "Letter From Ember" then
+ return 7292
+ elseif title == "Letter From Isobel" then
+ return 7293
+ elseif title == "Mezhun's Field Journal" then
+ return 2796
+ elseif title == "Nerulean's Guide to Phantoms Vol. II" then
+ return 3049
+ elseif title == "Ode to a Torchbug" then
+ return 2954
+ elseif title == "On Soul Shriven, vol 3" then
+ return 1551
+ elseif title == "An Orc Weaponsmith In Murkmire, Part 1" then -- real name is "From Wrothgar to Lilmoth: A Smith's Tale, Vol 1"
+ return 2850
+ elseif title == "An Orc Weaponsmith In Murkmire, Part 2" then -- real name is "From Wrothgar to Lilmoth: A Smith's Tale, Vol 2"
+ return 2851
+ elseif title == "An Orc Weaponsmith In Murkmire, Part 3" then -- real name is "From Wrothgar to Lilmoth: A Smith's Tale, Vol 3"
+ return 2852
+ elseif title == "Orcthane's Orders" then
+ return 439
+ elseif title == "Plea to Maximinus" then
+ return 2659
+ elseif title == "PRISONER: CLARISSE LAURENT" then
+ return 2908
+ elseif title == "PRISONER: RAYNOR VANOS" then
+ return 2907
+ elseif title == "PRISONER: TELENGER" then
+ return 2909
+ elseif title == "Report on Dominion Activities" then
+ return 147
+ elseif title == "Royal Messenger's Fate" then
+ return 2701
+ elseif title == "Seeking New Members!" then
+ return 7168
+ elseif title == "Six Are the Walking Ways" then
+ return 4445
+ elseif title == "The Song of the Word" then
+ return 4446
+ elseif title == "Southern Elsweyr Needs You!" then
+ return 5697
+ elseif title == "Statue of Amminus Entius" then
+ return 3419
+ elseif title == "Statue of Cavor Merula" then
+ return 3416
+ elseif title == "Statue of Justia Desticus" then
+ return 3417
+ elseif title == "Statue of Rusio Olo" then
+ return 3418
+ elseif title == "Terran's Notes" then
+ return 3047
+ elseif title == "The Tomb of Ja'darri" then
+ return 5737
+ elseif title == "Torag ag Krazak, Uz" then
+ return 3089
+ elseif title == "Tribute Challengers - Novice Tournament" then
+ return 7169
+ elseif title == "Ushutha's Journal" then
+ return 3162
+ elseif title == "The Year 2920, Vol. 28" then
+ return 2945
+ end
+
+ if not self.globalSavedVars.failedDeprecation then
+ self.globalSavedVars.failedDeprecation = { librarianBookId = 100000, bookList = {} }
+ end
+
+ for _, book in ipairs(self.globalSavedVars.failedDeprecation.bookList) do
+ if book.title == title then
+ return book.bookId
+ end
+ end
+
+ local nextBookId = self.globalSavedVars.failedDeprecation.librarianBookId
+ local newFailedDeprecation = { title = title, bookId = nextBookId }
+ table.insert(self.globalSavedVars.failedDeprecation.bookList, newFailedDeprecation)
+ self.globalSavedVars.failedDeprecation.librarianBookId = nextBookId + 1
+
+ return nextBookId
+end
+
+function Librarian:UpdateSavedVariables()
+ -- before version 3.0 there was no saveVersion
+ -- In this version, the bookId is now used as identifier instead of the title (because several book have the same title)
+ -- Also unreadPerCollections was added
+ if not self.globalSavedVars.saveVersion then
+ self.globalSavedVars.saveVersion = 1
+
+ -- if this player doesn't know any book yet, no need to go further
+ if next(self.books) ~= nil then
+ local GetLoreBookInfo, ReadLoreBook = GetLoreBookInfo, ReadLoreBook
+ local bookIndexes = {
+ categoryIndex = 0,
+ collectionIndex = 0,
+ bookIndex = 0,
+ numCollections = 0,
+ totalBooks = 0,
+ }
+ while true do
+ if not GetNextBookIndex(bookIndexes) then
+ break
+ end
+
+ local title, _, _, bookId = GetLoreBookInfo(bookIndexes.categoryIndex, bookIndexes.collectionIndex, bookIndexes.bookIndex)
+ local book = nil
+ for _,bookIt in pairs(self.books) do
+ if bookIt.title == title then
+ book = bookIt
+ break
+ end
+ end
+ if book then
+ if not book.bookId then
+ book.bookId = bookId
+ else -- there is a collision (2 books with same name) so we add an entry for the new one
+ local newBook = { bookId = bookId, title = title }
+ self:AddBookToGlobalSave(newBook)
+ newBook.timeStamp = book.timeStamp
+ end
+ end
+ end
+
+ -- now we can erase all the field that are useless (ESO API is performant enough to get these data only when needed)
+ -- it will also help keeping the save small and avoid issues with corrupted save
+ for _,book in pairs(self.books) do
+ if book.bookId then
+ book.title = nil
+ book.body = nil
+ book.medium = nil
+ book.showTitle = nil
+ book.wordCount = nil
+ else
+ book.bookId = self:GetBookIdWithTitle(book.title)
+ end
+ end
+ end
+ end
+
+ if not self.localSavedVars.saveVersion then
+ self.localSavedVars.saveVersion = 1
+ self.localSavedVars.unreadPerCollections = {} -- erase whatever is already inside (just in case)
+ self.unreadPerCollections = self.localSavedVars.unreadPerCollections
+
+ local GetLoreBookInfo, ReadLoreBook = GetLoreBookInfo, ReadLoreBook
+ local bookIndexes = {
+ categoryIndex = 0,
+ collectionIndex = 0,
+ bookIndex = 0,
+ numCollections = 0,
+ totalBooks = 0,
+ }
+ while true do
+ if not GetNextBookIndex(bookIndexes) then
+ break
+ end
+
+ local title, _, known, bookId = GetLoreBookInfo(bookIndexes.categoryIndex, bookIndexes.collectionIndex, bookIndexes.bookIndex)
+
+ if known then
+ local characterBook = nil
+ for _,characterBookIt in ipairs(self.characterBooks) do
+ if characterBookIt.title == title then
+ characterBook = characterBookIt
+ break
+ end
+ end
+
+ if characterBook then
+ if not characterBook.bookId then
+ characterBook.bookId = bookId
+ else
+ local newCharacterBook = { title = title, timeStamp = characterBook.timeStamp, bookId = bookId }
+ table.insert(self.characterBooks, newCharacterBook)
+ end
+
+ local book = self:FindBook(bookId)
+ if book and book.unread then
+ self:AddUnreadBookInCollection(bookIndexes.categoryIndex, bookIndexes.collectionIndex)
+ end
+ end
+ end
+ end
+
+ -- now we can remove the title from the characterBooks and rely only on the bookId (it saves space)
+ for _,characterBook in ipairs(self.characterBooks) do
+ if characterBook.bookId then
+ characterBook.title = nil
+ else
+ characterBook.bookId = self:GetBookIdWithTitle(characterBook.title)
+ end
+ end
+ end
+end
diff --git a/Librarian.lua b/Librarian.lua
index 36f6e82..a0230e1 100644
--- a/Librarian.lua
+++ b/Librarian.lua
@@ -1,4 +1,5 @@
Librarian = ZO_SortFilterList:Subclass()
+Librarian.name = "Librarian"
Librarian.defaults = {}
Librarian.menuSettings = {
name = "LibrarianOptions",
@@ -99,6 +100,9 @@ function Librarian:AddLoreReaderUnreadToggle()
end
local function IsSameBook(book, title)
+ if book.title then
+ return book.title == title
+ end
local categoryIndex, collectionIndex, bookIndex = GetLoreBookIndicesFromBookId(book.bookId)
local bookTitle = GetLoreBookInfo(categoryIndex, collectionIndex, bookIndex)
return bookTitle == title
@@ -122,6 +126,10 @@ function Librarian:AddLoreReaderUnreadToggle()
return GetString(LIBRARIAN_MARK_UNREAD)
end
end,
+ visible = function()
+ local book = self:FindBook(self.lastShownBookId)
+ return book and IsSameBook(book, LORE_READER.titleText)
+ end,
keybind = "UI_SHORTCUT_SECONDARY",
callback = function()
local book = self:FindBook(self.lastShownBookId)
@@ -133,6 +141,8 @@ function Librarian:AddLoreReaderUnreadToggle()
end
}
table.insert(readerKeybinds, toggleKeybind)
+
+ self.loreReaderKeybinds = readerKeybinds
end
self.loreReaderUnreadIndicator = WINDOW_MANAGER:CreateControl("LibrarianLoreReaderUnreadIndicator", ZO_LoreReaderBookContainer, CT_TEXTURE)
@@ -238,8 +248,8 @@ function Librarian:AddLoreLibraryIcons()
if selectedRow then
local book = self:FindBook(selectedRow.bookId)
if not book then
- self:AddBook(selectedRow.bookId, selectedRow.text:GetText(), true)
- book = self:FindBook(selectedRow.bookId)
+ book = { bookId = selectedRow.bookId, title = selectedRow.text:GetText() }
+ self:AddBook(book, true)
end
if book then
@@ -283,130 +293,6 @@ function Librarian:AddLoreLibraryIcons()
LORE_LIBRARY.navigationTree.templateInfo["ZO_LabelHeader"].equalityFunction = navigationEntryTemplateInfo.equalityFunction
end
-local function GetNextBookIndex(bookIndexes)
- if bookIndexes.bookIndex >= bookIndexes.totalBooks then
- if bookIndexes.collectionIndex >= bookIndexes.numCollections then
- if bookIndexes.categoryIndex >= GetNumLoreCategories() then
- return false
- else
- bookIndexes.categoryIndex = bookIndexes.categoryIndex + 1
- bookIndexes.numCollections = select(2, GetLoreCategoryInfo(bookIndexes.categoryIndex))
- bookIndexes.collectionIndex = 0
- end
- end
- bookIndexes.collectionIndex = bookIndexes.collectionIndex + 1
- bookIndexes.totalBooks = select(4, GetLoreCollectionInfo(bookIndexes.categoryIndex, bookIndexes.collectionIndex))
- bookIndexes.bookIndex = 0
- end
- bookIndexes.bookIndex = bookIndexes.bookIndex + 1
- return true
-end
-
-function Librarian:UpdateSavedVariables()
- -- before version 3.0 there was no saveVersion
- -- In this version, the bookId is now used as identifier instead of the title (because several book have the same title)
- -- Also unreadPerCollections was added
- if not self.globalSavedVars.saveVersion then
- self.globalSavedVars.saveVersion = 1
-
- -- if this player doesn't know any book yet, no need to go further
- if next(self.books) ~= nil then
- local GetLoreBookInfo, ReadLoreBook = GetLoreBookInfo, ReadLoreBook
- local bookIndexes = {
- categoryIndex = 0,
- collectionIndex = 0,
- bookIndex = 0,
- numCollections = 0,
- totalBooks = 0,
- }
- while true do
- if not GetNextBookIndex(bookIndexes) then
- break
- end
-
- local title, _, _, bookId = GetLoreBookInfo(bookIndexes.categoryIndex, bookIndexes.collectionIndex, bookIndexes.bookIndex)
- local book = nil
- for _,bookIt in pairs(self.books) do
- if bookIt.title == title then
- book = bookIt
- break
- end
- end
- if book then
- if not book.bookId then
- book.bookId = bookId
- else -- there is a collision (2 books with same name) so we add an entry for the new one
- self:AddBookToGlobalSave(bookId)
- end
- end
- end
-
- -- now we can erase all the field that are useless (ESO API is performant enough to get these data only when needed)
- -- it will also help keeping the save small and avoid issues with corrupted save
- for _,book in pairs(self.books) do
- book.title = nil
- book.body = nil
- book.medium = nil
- book.showTitle = nil
- book.wordCount = nil
- end
- end
- end
-
- if not self.localSavedVars.saveVersion then
- self.localSavedVars.saveVersion = 1
- self.localSavedVars.unreadPerCollections = {} -- erase whatever is already inside (just in case)
- self.unreadPerCollections = self.localSavedVars.unreadPerCollections
-
- local GetLoreBookInfo, ReadLoreBook = GetLoreBookInfo, ReadLoreBook
- local bookIndexes = {
- categoryIndex = 0,
- collectionIndex = 0,
- bookIndex = 0,
- numCollections = 0,
- totalBooks = 0,
- }
- while true do
- if not GetNextBookIndex(bookIndexes) then
- break
- end
-
- local title, _, known, bookId = GetLoreBookInfo(bookIndexes.categoryIndex, bookIndexes.collectionIndex, bookIndexes.bookIndex)
-
- if known then
- local characterBook = nil
- for _,characterBookIt in ipairs(self.characterBooks) do
- if characterBookIt.title == title then
- characterBook = characterBookIt
- break
- end
- end
-
- if characterBook then
- if not characterBook.bookId then
- characterBook.bookId = bookId
- else
- local newCharacterBook = { title = title, timeStamp = characterBook.timeStamp, bookId = bookId }
- table.insert(self.characterBooks, newCharacterBook)
- end
-
- local book = self:FindBook(bookId)
- if book and book.unread then
- self:AddUnreadBookInCollection(bookIndexes.categoryIndex, bookIndexes.collectionIndex)
- end
- end
- end
- end
-
- -- now we can remove the title from the characterBooks and rely only on the bookId (it saves space)
- for _,characterBook in ipairs(self.characterBooks) do
- characterBook.title = nil
- end
- end
-
-
-end
-
function Librarian:InitializeKeybindStripDescriptors()
self.keybindStripDescriptor =
{
@@ -512,7 +398,8 @@ function Librarian:ImportFromLoreLibrary()
local title, _, known, bookId = GetLoreBookInfo(categoryIndex, collectionIndex, bookIndex)
if known then
if not self:FindCharacterBook(bookId) then
- self:AddBook(bookId, title, false)
+ book = { bookId = bookId, title = title }
+ self:AddBook(book, false)
hasImportedBooks = true
end
end
@@ -537,8 +424,12 @@ function Librarian:BuildMasterList()
local function ShouldDisplayBook(book)
if not self.settings.showHiddenBook then
local category, collection = GetLoreBookIndicesFromBookId(book.bookId)
- local hiddenCollection = select(5, GetLoreCollectionInfo(category, collection))
- if hiddenCollection then
+ if category and collection then
+ local hiddenCollection = select(5, GetLoreCollectionInfo(category, collection))
+ if hiddenCollection then
+ return false
+ end
+ else
return false
end
end
@@ -553,12 +444,18 @@ function Librarian:BuildMasterList()
local data = self.masterList[i]
for k,v in pairs(book) do
- data[k] = v
+ if k == "body" then
+ data[k] = table.concat(book.body)
+ else
+ data[k] = v
+ end
end
-- because we reuse the same list between 2 refresh, the data may already be filled up so no need to recompute it, these won't change
- if not data.categoryIndex or not data.collectionIndex or not data.bookIndex or not data.title or not data.body or not data.wordCount then
+ if not data.categoryIndex or not data.collectionIndex or not data.bookIndex then
data.categoryIndex, data.collectionIndex, data.bookIndex = GetLoreBookIndicesFromBookId(book.bookId)
+ end
+ if data.categoryIndex and data.collectionIndex and data.bookIndex and (not data.title or not data.body or not data.wordCount) then
data.title = GetLoreBookInfo(data.categoryIndex, data.collectionIndex, data.bookIndex)
data.body = ReadLoreBook(data.categoryIndex, data.collectionIndex, data.bookIndex)
@@ -676,25 +573,38 @@ function Librarian:FindBook(bookId)
end
end
-function Librarian:AddBookToGlobalSave(bookId)
- local book = { bookId = bookId, timeStamp = GetTimeStamp(), unread = true }
+function Librarian:AddBookToGlobalSave(book)
+ book.timeStamp = GetTimeStamp()
+ book.unread = true
+
+ local categoryIndex, collectionIndex, bookIndex = GetLoreBookIndicesFromBookId(book.bookId)
+ if categoryIndex and collectionIndex and bookIndex then
+ -- if these indexes exist in the API, this mean that we will be able to get these info when needed (so no need to save them)
+ book.title = nil
+ book.body = nil
+ book.medium = nil
+ book.showTitle = nil
+ book.wordCount = nil
+ end
+
table.insert(self.books, book)
- return book
end
-function Librarian:AddBook(bookId, bookTitle, refreshDataRightAway)
- if not self:FindCharacterBook(bookId) then
- local book = self:FindBook(bookId)
- if not book then
- book = self:AddBookToGlobalSave(bookId)
+function Librarian:AddBook(book, refreshDataRightAway)
+ if not self:FindCharacterBook(book.bookId) then
+ local bookTitle = book.title -- storing it because AddBookToGlobalSave will delete it if we can retrieve it thanks to ESO API
+ if not self:FindBook(book.bookId) then
+ self:AddBookToGlobalSave(book)
end
- local characterBook = { bookId = bookId, timeStamp = GetTimeStamp() }
+ local characterBook = { bookId = book.bookId, timeStamp = GetTimeStamp() }
table.insert(self.characterBooks, characterBook)
if book.unread then
- local categoryIndex, collectionIndex = GetLoreBookIndicesFromBookId(bookId)
- self:AddUnreadBookInCollection(categoryIndex, collectionIndex)
+ local categoryIndex, collectionIndex = GetLoreBookIndicesFromBookId(book.bookId)
+ if categoryIndex and collectionIndex then
+ self:AddUnreadBookInCollection(categoryIndex, collectionIndex)
+ end
end
if refreshDataRightAway then
@@ -752,8 +662,12 @@ end
function Librarian:ReadBook(data)
self.lastShownBookId = data.bookId
- local body, medium, showTitle = ReadLoreBook(data.categoryIndex, data.collectionIndex, data.bookIndex)
- LORE_READER:SetupBook(data.title, body, medium, showTitle)
+ if data.categoryIndex and data.collectionIndex and data.bookIndex then
+ local body, medium, showTitle = ReadLoreBook(data.categoryIndex, data.collectionIndex, data.bookIndex)
+ LORE_READER:SetupBook(data.title, body, medium, showTitle)
+ else
+ LORE_READER:SetupBook(data.title, data.body, data.medium, data.showTitle)
+ end
SCENE_MANAGER:Push("loreReaderInteraction")
-- PlaySound(LORE_READER.OpenSound)
@@ -804,9 +718,12 @@ function Librarian.SlashCommand(args)
end
function Librarian.OnShowBook(eventCode, title, body, medium, showTitle, bookId)
- LIBRARIAN:AddBook(bookId, title, true)
-
+ local book = { title = title, body = body, medium = medium, showTitle = showTitle, bookId = bookId }
+ LIBRARIAN:AddBook(book, true)
LIBRARIAN.lastShownBookId = bookId
+ if LIBRARIAN.loreReaderKeybinds then
+ KEYBIND_STRIP:UpdateKeybindButtonGroup(LIBRARIAN.loreReaderKeybinds)
+ end
end
function Librarian.OnMouseEnterRow(control)
@@ -822,13 +739,13 @@ function Librarian.OnMouseUpRow(control, button, upInside)
end
function Librarian.OnAddonLoaded(event, addon)
- if addon == "Librarian" then
- EVENT_MANAGER:UnregisterForEvent("Librarian", EVENT_ADD_ON_LOADED)
+ if addon == Librarian.name then
+ EVENT_MANAGER:UnregisterForEvent(Librarian.name, EVENT_ADD_ON_LOADED)
LIBRARIAN = Librarian:New()
- EVENT_MANAGER:RegisterForEvent("Librarian", EVENT_SHOW_BOOK, Librarian.OnShowBook)
+ EVENT_MANAGER:RegisterForEvent(Librarian.name, EVENT_SHOW_BOOK, Librarian.OnShowBook)
end
end
SLASH_COMMANDS[Librarian.slashCommandText] = Librarian.SlashCommand
-EVENT_MANAGER:RegisterForEvent("Librarian", EVENT_ADD_ON_LOADED, Librarian.OnAddonLoaded)
+EVENT_MANAGER:RegisterForEvent(Librarian.name, EVENT_ADD_ON_LOADED, Librarian.OnAddonLoaded)
diff --git a/Librarian.txt b/Librarian.txt
index 7047da9..cef9927 100644
--- a/Librarian.txt
+++ b/Librarian.txt
@@ -11,6 +11,7 @@
Librarian.lua
LibrarianSettings.lua
+Deprecation.lua
Librarian.xml
Bindings.xml