--[[ ------------------------------------------------------------------------------- -- NoThankYou, by Ayantir ------------------------------------------------------------------------------- This software is under : CreativeCommons CC BY-NC-SA 4.0 Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) You are free to: Share — copy and redistribute the material in any medium or format Adapt — remix, transform, and build upon the material The licensor cannot revoke these freedoms as long as you follow the license terms. Under the following terms: Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. NonCommercial — You may not use the material for commercial purposes. ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. Please read full licence at : http://creativecommons.org/licenses/by-nc-sa/4.0/legalcode ]] local ADDON_NAME = "NoThankYou" local ADDON_VERSION = "5.3-p1" local ADDON_AUTHOR = "Ayantir, Garkin & iwontsay" local ADDON_WEBSITE = "http://www.esoui.com/downloads/info865-Nothankyou.html" local SV local defaults = { ava = 1, friends = false, boss = false, screenshot = false, enlightened = false, craftingResults = false, repair = false, alertTextExpiryDelay = 3, --seconds, 3 is default value used in AlertText emptyMail = true, guildAlerts = 0, guildAlertsGuilds = {}, raid = 0, raidToChat = true, raidGuilds = {}, motd = 0, motdGuilds = {}, nonstopHarvest = false, noCameraSpin = false, fenceDialog = false, ultimateSound = 0, disbandDialog = false, largeGroupDialog = false, marketAnnouncement = false, crownCrate = false, improveDialog = false, guildInvites = 0, luaMemory = 1, luaError = 1, dontReadBooks = false, noUniversalStones = false, noGuildLeave = 0, guildLeave = {}, autoLootItems = false, craftBag = false, groupZone = 1, dontShowLoreDiscoveries = 0, dontShowSkillProgression = 0, noReportOnItems = false, hideTamrielWayhsrines = 0, hideTamrielDungeons = 0, unownedHouses = 0, ownedHouses = 0, hideTamriel = false, dontAcceptWritQuest = false, } for i = 1, MAX_GUILDS do defaults.guildAlertsGuilds[i] = true defaults.raidGuilds[i] = true defaults.motdGuilds[i] = true end local recentMessages local isQueued = false local storedMessages = {} local function SafePrint(message) if IsPlayerActivated() then CHAT_SYSTEM:AddMessage(message) else table.insert(storedMessages, message) if not isQueued then isQueued = true EVENT_MANAGER:RegisterForEvent("NOTY_Print", EVENT_PLAYER_ACTIVATED, function(event) EVENT_MANAGER:UnregisterForEvent("NOTY_Print", event) for i, message in ipairs(storedMessages) do CHAT_SYSTEM:AddMessage(message) end ZO_ClearNumericallyIndexedTable(storedMessages) isQueued = false end) end end end --AvA messages local function HookAvAMessages() local handlers = ZO_CenterScreenAnnounce_GetHandlers() local avaEvents = { EVENT_ARTIFACT_CONTROL_STATE, EVENT_KEEP_GATE_STATE_CHANGED, EVENT_CORONATE_EMPEROR_NOTIFICATION, EVENT_DEPOSE_EMPEROR_NOTIFICATION, EVENT_IMPERIAL_CITY_ACCESS_GAINED_NOTIFICATION, EVENT_IMPERIAL_CITY_ACCESS_LOST_NOTIFICATION, } local function HookAvAEventHandler(event) local original = handlers[event] handlers[event] = function(...) if IsPlayerInAvAWorld() then return original(...) else if SV.ava == 1 then local _,_,msg = original(...) SafePrint(msg) elseif SV.ava == 2 then return else return original(...) end end end end for i = 1, #avaEvents do HookAvAEventHandler(avaEvents[i]) end --filter centerscreen announcements which are already in queue if not IsPlayerInAvAWorld() then local messageQueue = CENTER_SCREEN_ANNOUNCE.displayQueue for i = #messageQueue, 1, -1 do for eventIndex = 1, #avaEvents do local priority = CENTER_SCREEN_ANNOUNCE:GetPriority(avaEvents[eventIndex]) if messageQueue[i].priority == priority then if SV.ava == 1 then SafePrint(messageQueue[i][2]) table.remove(messageQueue, i) break elseif SV.ava == 2 then table.remove(messageQueue, i) break end end end end end end --Group Zone messages local function HookGroupZoneMessages() local handlers = ZO_CenterScreenAnnounce_GetHandlers() local groupEvents = { EVENT_DISPLAY_ANNOUNCEMENT, } -- We only want to hide those specific announcement or will remove a lot more. local groupValues = { GetString(NOTY_ENTERING_GROUP_AREA), GetString(NOTY_LEAVING_GROUP_AREA), } local function HookGroupZoneEventHandler(event) local original = handlers[event] handlers[event] = function(title, description) for index, stringValue in pairs(groupValues) do if title == stringValue or description == stringValue then if SV.groupZone == 1 then SafePrint(stringValue) return elseif SV.groupZone == 2 then return else return original(title, description) end end end return original(title, description) end end for i = 1, #groupEvents do HookGroupZoneEventHandler(groupEvents[i]) end --filter centerscreen announcements which are already in queue local messageQueue = CENTER_SCREEN_ANNOUNCE.displayQueue for i = #messageQueue, 1, -1 do for eventIndex = 1, #groupEvents do local priority = CENTER_SCREEN_ANNOUNCE:GetPriority(groupEvents[eventIndex]) if messageQueue[i].priority == priority then for index, stringValue in pairs(groupValues) do if messageQueue[i][2] == stringValue then if SV.groupZone == 1 then SafePrint(messageQueue[i][2]) table.remove(messageQueue, i) break elseif SV.groupZone == 2 then table.remove(messageQueue, i) break end end end end end end end local function HookFriendsMessages() local handlers = ZO_ChatSystem_GetEventHandlers() local function EventHook() return SV.friends end ZO_PreHook(handlers, EVENT_FRIEND_PLAYER_STATUS_CHANGED, EventHook) end local function BossAlertTextsHook() local handlers = ZO_AlertText_GetHandlers() local abilityErrorIds = { [162] = true, --"Flying creatures are immune to snares." [177] = true, --"This target is too powerful for that effect." } local function AbilityEventHook(errorStringId) if SV.boss then return abilityErrorIds[errorStringId] end end ZO_PreHook(handlers, EVENT_ABILITY_REQUIREMENTS_FAIL, AbilityEventHook) local actionResults = { [ACTION_RESULT_MISSING_EMPTY_SOUL_GEM] = true, -- "You must have a valid empty soul gem." } local function CombatEventHook(result, isError, ...) if isError and SV.boss then return actionResults[result] end end ZO_PreHook(handlers, EVENT_COMBAT_EVENT, CombatEventHook) end local function NoLootWindowOnItems() -- When LOOT_SETTING_AUTO_LOOT is on, the C++ LootAll() is called, all is handled by C++ side, and EVENT_CLOSE_LOOT is sent. -- All we can do is to use the LootAll() Lua function local function LootAllItems() local name, targetType, actionName, isOwned = GetLootTargetInfo() if name ~= "" then if targetType == INTERACT_TARGET_TYPE_ITEM then name = zo_strformat(SI_TOOLTIP_ITEM_NAME, name) elseif targetType == INTERACT_TARGET_TYPE_OBJECT then name = zo_strformat(SI_LOOT_OBJECT_NAME, name) elseif targetType == INTERACT_TARGET_TYPE_FIXTURE then name = zo_strformat(SI_TOOLTIP_FIXTURE_INSTANCE, name) end end if SV.autoLootItems then if not (targetType == INTERACT_TARGET_TYPE_ITEM and (isOwned == false and GetSetting(SETTING_TYPE_LOOT, LOOT_SETTING_AUTO_LOOT) == "1") or (isOwned and GetSetting(SETTING_TYPE_LOOT, LOOT_SETTING_AUTO_LOOT_STOLEN) == "1")) then SYSTEMS:GetObject("loot"):UpdateLootWindow(name, actionName, isOwned) else LOOT_SHARED:LootAllItems() end else SYSTEMS:GetObject("loot"):UpdateLootWindow(name, actionName, isOwned) end end EVENT_MANAGER:UnregisterForEvent("LOOT_SHARED", EVENT_LOOT_UPDATED) EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_LOOT_UPDATED, LootAllItems) end local function ScreenshotAlertHook() local handlers = ZO_AlertText_GetHandlers() local function EventHook() return SV.screenshot end ZO_PreHook(handlers, EVENT_SCREENSHOT_SAVED, EventHook) end local function EnlightenedAlertHook() local handlers = ZO_CenterScreenAnnounce_GetHandlers() local function EventHook() return SV.enlightened end ZO_PreHook(handlers, EVENT_PLAYER_ACTIVATED, EventHook) end local function CraftingResultAlertsHook() local blockedMessages = { [SI_SMITHING_BLACKSMITH_EXTRACTION_FAILED] = true, [SI_SMITHING_CLOTHIER_EXTRACTION_FAILED] = true, [SI_SMITHING_WOODWORKING_EXTRACTION_FAILED] = true, [SI_SMITHING_DECONSTRUCTION_LEVEL_PENALTY] = true, [SI_SMITHING_IMPROVEMENT_SUCCESS] = true, [SI_SMITHING_IMPROVEMENT_FAILED] = true, [SI_ALCHEMY_NO_YIELD] = true, [SI_ENCHANT_NO_YIELD] = true, } local function ZO_AlertNoSuppression_Hook(category, soundId, message) if SV.craftingResults then return blockedMessages[message] end end ZO_PreHook("ZO_AlertNoSuppression", ZO_AlertNoSuppression_Hook) end local function RepairAlertsHook() if ZO_GamepadStoreManager and ZO_GamepadStoreManager.RepairMessageBox then local function RepairMessageBox_Hook(...) return SV.repair end ZO_PreHook(ZO_GamepadStoreManager, "RepairMessageBox", RepairMessageBox_Hook) end end local function AlertTextThrottling() recentMessages = ZO_RecentMessages:New(SV.alertTextExpiryDelay * 1000) local function ZO_Alert_Hook(category, soundId, message) if message and message ~= "" then return not recentMessages:ShouldDisplayMessage(message) end return true end ZO_PreHook("ZO_Alert", ZO_Alert_Hook) local function ZO_SoundAlert_Hook(category, soundId) if soundId and soundId ~= "" then return not recentMessages:ShouldDisplayMessage(soundId) end return true end ZO_PreHook("ZO_SoundAlert", ZO_SoundAlert_Hook) end local function DeleteEmptyMailHook() local function Delete_Hook(self) if SV.emptyMail and self.mailId then if self:IsMailDeletable() then self:ConfirmDelete(self.mailId) return true end end end ZO_PreHook(MAIL_INBOX, "Delete", Delete_Hook) end local function NoUniversalStones() local function DisableUniversalCheckbox(_, craftSkill) if craftSkill == CRAFTING_TYPE_BLACKSMITHING or craftSkill == CRAFTING_TYPE_CLOTHIER or craftSkill == CRAFTING_TYPE_WOODWORKING then if GetCurrentSmithingStyleItemCount(ZO_ADJUSTED_UNIVERSAL_STYLE_ITEM_INDEX) == 0 then ZO_SmithingTopLevelCreationPanelStyleListUniversalStyleItem:SetHidden(true) else ZO_SmithingTopLevelCreationPanelStyleListUniversalStyleItem:SetHidden(false) end end end if SV.noUniversalStones then EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_CRAFTING_STATION_INTERACT, DisableUniversalCheckbox) else EVENT_MANAGER:UnregisterForEvent(ADDON_NAME, EVENT_CRAFTING_STATION_INTERACT) ZO_SmithingTopLevelCreationPanelStyleListUniversalStyleItem:SetHidden(false) end end local function NoGuildLeave() if SV.noGuildLeave == 1 then GUILD_HOME.keybindStripDescriptor[1].visible = function() return false end elseif SV.noGuildLeave == 2 and SV.guildLeave[GUILD_HOME.guildId] then GUILD_HOME.keybindStripDescriptor[1].visible = function() return false end else GUILD_HOME.keybindStripDescriptor[1].visible = function() return true end end end local function NoGuildLeavePreHook() ZO_PreHook(GUILD_HOME, "RefreshAll", NoGuildLeave) end local function GuildRosterAlertsHook() local function GetGuildIndex(guildId) for index = 1, GetNumGuilds() do if GetGuildId(index) == guildId then return index end end return 0 end local function OnGuildMemberAdded_Hook(self, guildId, displayName) if SV.guildAlerts == 1 then local index = GetGuildIndex(guildId) if SV.guildAlertsGuilds[index] then self:RefreshData() if DoesPlayerHaveGuildPermission(guildId, GUILD_PERMISSION_INVITE) then local data = self:FindDataByDisplayName(displayName) if data then local _, rawCharacterName = GetGuildMemberCharacterInfo(guildId, data.index) SafePrint(zo_strformat(SI_GUILD_ROSTER_ADDED, rawCharacterName, self.guildName)) end end return true end elseif SV.guildAlerts == 2 then local index = GetGuildIndex(guildId) if SV.guildAlertsGuilds[index] then self:RefreshData() return true end end end ZO_PreHook(ZO_GuildRosterManager or GUILD_ROSTER, "OnGuildMemberAdded", OnGuildMemberAdded_Hook) local function OnGuildMemberRemoved_Hook(self, guildId, rawCharacterName) if SV.guildAlerts == 1 then local index = GetGuildIndex(guildId) if SV.guildAlertsGuilds[index] then if DoesPlayerHaveGuildPermission(guildId, GUILD_PERMISSION_INVITE) then SafePrint(zo_strformat(SI_GUILD_ROSTER_REMOVED, rawCharacterName, self.guildName)) end self:RefreshData() return true end elseif SV.guildAlerts == 2 then local index = GetGuildIndex(guildId) if SV.guildAlertsGuilds[index] then self:RefreshData() return true end end end ZO_PreHook(ZO_GuildRosterManager or GUILD_ROSTER, "OnGuildMemberRemoved", OnGuildMemberRemoved_Hook) end --raid notifications local function HookRaidNotifications() local function BuildNotificationList_Hook(self) local function BuildMessageAndRemoveNotification(contacts, message, notificationId) local membersListShorten = "" local nbContacts = #contacts if nbContacts > 4 then local shortOthers = zo_strformat(GetString(NOTY_RAID_OTHERS), ZO_SELECTED_TEXT:Colorize((nbContacts - 2))) membersListShorten = zo_strformat(" (<<1>>, <<2>> <<3>>)", ZO_SELECTED_TEXT:Colorize(contacts[1]), ZO_SELECTED_TEXT:Colorize(contacts[2]), shortOthers) else local myContacts = "" for _, contactName in ipairs(contacts) do myContacts = myContacts .. ZO_SELECTED_TEXT:Colorize(contactName) .. ", " end membersListShorten = zo_strformat(" (<<1>>)", myContacts:sub(1, -3)) end message = string.gsub(message, GetString(NOTY_RAID_COMPLETE), zo_strformat("<<1>><<2>> ", membersListShorten, GetString(NOTY_RAID_COMPLETE))) SafePrint(message) RemoveRaidScoreNotification(notificationId) end if SV.raid == 0 and SV.raidToChat then for index = 1, GetNumRaidScoreNotifications() do local notificationId = GetRaidScoreNotificationId(index) local numRaidMembers = GetNumRaidScoreNotificationMembers(notificationId) local hasGuildMember = false local hasFriend = false local contacts = {} for raidMemberIndex = 1, numRaidMembers do local displayName, _, isFriend, isGuildMember = GetRaidScoreNotificationMemberInfo(notificationId, raidMemberIndex) if isFriend or isGuildMember then table.insert(contacts, displayName) end hasFriend = hasFriend or isFriend hasGuildMember = hasGuildMember or isGuildMember end if hasFriend or hasGuildMember then local raidId, raidScore = GetRaidScoreNotificationInfo(notificationId) local raidName = GetRaidName(raidId) local message = self:CreateMessage(raidName, raidScore, hasFriend, hasGuildMember) BuildMessageAndRemoveNotification(contacts, message, notificationId) end end elseif SV.raid == 1 then for index = 1, GetNumRaidScoreNotifications() do local notificationId = GetRaidScoreNotificationId(index) local numRaidMembers = GetNumRaidScoreNotificationMembers(notificationId) local hasGuildMember = false local showNotification = false local contacts = {} for raidMemberIndex = 1, numRaidMembers do local displayName, _, isFriend, isGuildMember = GetRaidScoreNotificationMemberInfo(notificationId, raidMemberIndex) showNotification = showNotification or isFriend if isFriend then table.insert(contacts, displayName) end hasGuildMember = hasGuildMember or isGuildMember end if not showNotification then RemoveRaidScoreNotification(notificationId) elseif SV.raidToChat then local raidId, raidScore = GetRaidScoreNotificationInfo(notificationId) local raidName = GetRaidName(raidId) local message = self:CreateMessage(raidName, raidScore, showNotification, hasGuildMember) BuildMessageAndRemoveNotification(contacts, message, notificationId) end end elseif SV.raid == 2 then for index = 1, GetNumRaidScoreNotifications() do local notificationId = GetRaidScoreNotificationId(index) local numRaidMembers = GetNumRaidScoreNotificationMembers(notificationId) local showNotification = false local hasFriend = false local guildMembers = {} local contacts = {} for raidMemberIndex = 1, numRaidMembers do local displayName, _, isFriend, isGuildMember = GetRaidScoreNotificationMemberInfo(notificationId, raidMemberIndex) hasFriend = hasFriend or isFriend if isGuildMember then table.insert(guildMembers, displayName) end end for _, displayName in ipairs(guildMembers) do for guildIndex = 1, GetNumGuilds() do if SV.raidGuilds[guildIndex] then local guildId = GetGuildId(guildIndex) for guildMemberIndex = 1, GetNumGuildMembers(guildId) do local displayName = GetGuildMemberInfo(guildId, guildMemberIndex) if displayName == displayName then showNotification = true table.insert(contacts, displayName) end end end end end if not showNotification then RemoveRaidScoreNotification(notificationId) elseif SV.raidToChat then local raidId, raidScore = GetRaidScoreNotificationInfo(notificationId) local raidName = GetRaidName(raidId) local message = self:CreateMessage(raidName, raidScore, hasFriend, #guildMembers > 0) BuildMessageAndRemoveNotification(contacts, message, notificationId) end end elseif SV.raid == 3 then for index = 1, GetNumRaidScoreNotifications() do local notificationId = GetRaidScoreNotificationId(index) RemoveRaidScoreNotification(notificationId) end end end ZO_PreHook(ZO_LeaderboardRaidProvider, "BuildNotificationList", BuildNotificationList_Hook) end --Guild MotD notifications local function HookMotDNotifications() local function BuildNotificationList_Hook(self) if self.sv then if SV.motd == 1 then ZO_ClearNumericallyIndexedTable(self.list) for i = 1, GetNumGuilds() do local guildId = GetGuildId(i) local guildName = GetGuildName(guildId) local savedMotD = self.sv[guildName] local currentMotD = GetGuildMotD(guildId) if savedMotD ~= currentMotD then local guildAlliance = GetGuildAlliance(guildId) local allianceIcon = zo_iconFormat(GetAllianceBannerIcon(guildAlliance), 24, 24) local message = zo_strformat("<<X:1>> |cFFFFFF<<2>>|r\n<<3>>", allianceIcon, guildName, currentMotD) SafePrint(message) end self.sv[guildName] = currentMotD end return true elseif SV.motd == 2 then ZO_ClearNumericallyIndexedTable(self.list) for i = 1, GetNumGuilds() do local guildId = GetGuildId(i) local guildName = GetGuildName(guildId) self.sv[guildName] = GetGuildMotD(guildId) end return true end end end ZO_PreHook(ZO_GuildMotDProvider, "BuildNotificationList", BuildNotificationList_Hook) end --CraftBagNotifications notifications local function HookCraftBagNotifications() local function BuildNotificationList_Hook(self) if SV.craftBag then ZO_ClearNumericallyIndexedTable(self.list) return true end end ZO_PreHook(ZO_CraftBagAutoTransferProvider, "BuildNotificationList", BuildNotificationList_Hook) end --Reticle Hook local function HookReticleTake() local function DisableReticleTake_Hook(interactionPossible) if interactionPossible then if SV.reticleTake then local action, interactableName = GetGameCameraInteractableActionInfo() if action and interactableName then if (action == GetString(NOTY_INTERACTION_TAKE)) then if (interactableName == GetString(NOTY_INSECT_BUTTERFLY) or interactableName == GetString(NOTY_INSECT_TORCHBUG) or interactableName == GetString(NOTY_INSECT_WASP) or interactableName == GetString(NOTY_INSECT_FLESHFLIES)) then return true end end end end end return false end ZO_PreHook(RETICLE, "TryHandlingInteraction", DisableReticleTake_Hook) end --Guild invite notifications local function HookGuildInvitesNotifications() local function BuildNotificationList_Hook(self) ZO_ClearNumericallyIndexedTable(self.list) if SV.guildInvites == 0 or (SV.guildInvites == 2 and GetNumGuilds() < MAX_GUILDS) then for i = 1, GetNumGuildInvites() do local guildId, guildName, guildAlliance, inviterDisplayName, note = GetGuildInviteInfo(i) local secsSinceRequest = 0 local formattedInviterName = ZO_FormatUserFacingDisplayName(inviterDisplayName) local message = self:CreateMessage(guildAlliance, guildName, formattedInviterName) self.list[i] = { dataType = NOTIFICATIONS_REQUEST_DATA, guildId = guildId, guildAlliance = guildAlliance, guildName = guildName, displayName = inviterDisplayName, notificationType = NOTIFICATION_TYPE_GUILD, secsSinceRequest = ZO_NormalizeSecondsSince(secsSinceRequest), note = note, message = message, shortDisplayText = formattedInviterName, controlsOwnSounds = true, } end end return true end ZO_PreHook(ZO_GuildInviteProvider, "BuildNotificationList", BuildNotificationList_Hook) end local function HookPlayerToPlayerGuildInvite() local INTERACT_TYPE_GUILD_INVITE = 7 PLAYER_TO_PLAYER.control:UnregisterForEvent(EVENT_GUILD_INVITE_ADDED) PLAYER_TO_PLAYER.control:RegisterForEvent(EVENT_GUILD_INVITE_ADDED, function (eventCode, guildId, guildName, guildAlliance, inviterName) if SV.guildInvites == 0 or (SV.guildInvites == 2 and GetNumGuilds() < MAX_GUILDS) then local allianceIconSize = 24 if IsInGamepadPreferredMode() then allianceIconSize = 36 end local formattedInviterName = ZO_FormatUserFacingDisplayName(inviterName) local guildNameAlliance = zo_iconTextFormat(GetAllianceBannerIcon(guildAlliance), allianceIconSize, allianceIconSize, ZO_SELECTED_TEXT:Colorize(guildName)) local data = PLAYER_TO_PLAYER:AddPromptToIncomingQueue(INTERACT_TYPE_GUILD_INVITE, nil, formattedInviterName, zo_strformat(SI_PLAYER_TO_PLAYER_INCOMING_GUILD_REQUEST, ZO_SELECTED_TEXT:Colorize(formattedInviterName), guildNameAlliance), function() AcceptGuildInvite(guildId) end, function() RejectGuildInvite(guildId) end, function() PLAYER_TO_PLAYER:RemoveFromIncomingQueue(INTERACT_TYPE_GUILD_INVITE, formattedInviterName) end) data.guildId = guildId end end) end -- Aya: Don't interrupt on mailScenes anymore due to RequestOpenMailbox() - sec issue I guess local function DontInterruptHarvesting() local function Show_Hook(self) if SV.nonstopHarvest then EndPendingInteraction() self:OnShown() return true end end ZO_PreHook(END_IN_WORLD_INTERACTIONS_FRAGMENT, "Show", Show_Hook) end local function DontReadBooks() local function OnShowBook(eventCode, title, body, medium, showTitle) local willShow = LORE_READER:Show(title, body, medium, showTitle) if willShow then PlaySound(LORE_READER.OpenSound) else EndInteraction(INTERACTION_BOOK) end end local function OnDontShowBook() EndInteraction(INTERACTION_BOOK) end if SV.dontReadBooks then LORE_READER.control:UnregisterForEvent(EVENT_SHOW_BOOK) LORE_READER.control:RegisterForEvent(EVENT_SHOW_BOOK, OnDontShowBook) else LORE_READER.control:UnregisterForEvent(EVENT_SHOW_BOOK) LORE_READER.control:RegisterForEvent(EVENT_SHOW_BOOK, OnShowBook) end end local function DontShowLoreDiscoveries() local handlers = ZO_CenterScreenAnnounce_GetHandlers() local loreEvents = { EVENT_LORE_BOOK_LEARNED, EVENT_LORE_BOOK_LEARNED_SKILL_EXPERIENCE, EVENT_LORE_COLLECTION_COMPLETED, EVENT_LORE_COLLECTION_COMPLETED_SKILL_EXPERIENCE, } local function HookLoreLibraryEventHandler(event) local original = handlers[event] handlers[event] = function(...) if SV.dontShowLoreDiscoveries == 1 then local _, _, msg = original(...) SafePrint(msg) return elseif SV.dontShowLoreDiscoveries == 2 then return else return original(...) end end end for i = 1, #loreEvents do HookLoreLibraryEventHandler(loreEvents[i]) end --filter centerscreen announcements which are already in queue local messageQueue = CENTER_SCREEN_ANNOUNCE.displayQueue for i = #messageQueue, 1, -1 do for eventIndex = 1, #loreEvents do local priority = CENTER_SCREEN_ANNOUNCE:GetPriority(loreEvents[eventIndex]) if messageQueue[i].priority == priority then if SV.dontShowLoreDiscoveries == 1 then SafePrint(messageQueue[i][2]) table.remove(messageQueue, i) break elseif SV.dontShowLoreDiscoveries == 2 then table.remove(messageQueue, i) break end end end end end local function DontShowSkillProgression() local handlers = ZO_CenterScreenAnnounce_GetHandlers() local skillEvents = { EVENT_ABILITY_PROGRESSION_RANK_UPDATE, } local function HookLoreLibraryEventHandler(event) local original = handlers[event] handlers[event] = function(progressionIndex, ...) local _, _, _, atMorph = GetAbilityProgressionXPInfo(progressionIndex) if not atMorph then if SV.dontShowSkillProgression == 1 then local _, _, msg = original(progressionIndex, ...) SafePrint(msg) return elseif SV.dontShowSkillProgression == 2 then return else return original(progressionIndex, ...) end end return original(progressionIndex, ...) end end for i = 1, #skillEvents do HookLoreLibraryEventHandler(skillEvents[i]) end --filter centerscreen announcements which are already in queue local messageQueue = CENTER_SCREEN_ANNOUNCE.displayQueue for i = #messageQueue, 1, -1 do for eventIndex = 1, #skillEvents do local priority = CENTER_SCREEN_ANNOUNCE:GetPriority(skillEvents[eventIndex]) if messageQueue[i].priority == priority then if SV.dontShowSkillProgression == 1 then SafePrint(messageQueue[i][2]) table.remove(messageQueue, i) break elseif SV.dontShowSkillProgression == 2 then table.remove(messageQueue, i) break end end end end end local scenes = {} local function DontRotateGameCamera() local emotesFragments = { FRAME_PLAYER_FRAGMENT, FRAME_EMOTE_FRAGMENT_INVENTORY, FRAME_EMOTE_FRAGMENT_SKILLS, FRAME_EMOTE_FRAGMENT_JOURNAL, FRAME_EMOTE_FRAGMENT_MAP, FRAME_EMOTE_FRAGMENT_SOCIAL, FRAME_EMOTE_FRAGMENT_AVA, FRAME_EMOTE_FRAGMENT_SYSTEM, FRAME_EMOTE_FRAGMENT_LOOT, FRAME_EMOTE_FRAGMENT_CHAMPION, } local blacklistedScenes = { market = true, crownCrateGamepad = true, crownCrateKeyboard = true, keyboard_housing_furniture_scene = true, gamepad_housing_furniture_scene = true, dyeStampConfirmationGamepad = true, dyeStampConfirmationKeyboard = true, } if SV.noCameraSpin then for name, scene in pairs(SCENE_MANAGER.scenes) do if not blacklistedScenes[name] then local sceneToSave = true for _, fragmentToRemove in ipairs(emotesFragments) do if scene:HasFragment(fragmentToRemove) then scene:RemoveFragment(fragmentToRemove) if sceneToSave then sceneToSave = false scenes[name] = scene scenes[name].toRestore = {} end table.insert(scenes[name].toRestore, fragmentToRemove) end end end end else for name, scene in pairs(scenes) do if scene.toRestore then for index, fragment in ipairs(scene.toRestore) do scene:AddFragment(fragment) end end end end end local function HookFenceDialog() local function ShowDialog_Hook(name, data) if name == "CANT_BUYBACK_FROM_FENCE" then if SV.fenceDialog then SellInventoryItem(data.bag, data.slot, data.stackCount) return true end end end ZO_PreHook("ZO_Dialogs_ShowDialog", ShowDialog_Hook) end local function HookPlaySound() local function PlaySound_Hook(soundId) if (soundId == SOUNDS.ABILITY_ULTIMATE_READY) then if SV.ultimateSound == 1 then return (not IsUnitInCombat("player")) elseif SV.ultimateSound == 2 then return IsUnitInCombat("player") elseif SV.ultimateSound == 3 then return true end end end ZO_PreHook("PlaySound", PlaySound_Hook) end local function HookDisbandDialog() local function ShowDialog_Hook(name, data) if name == "GROUP_DISBAND_DIALOG" then if SV.disbandDialog then GroupDisband() return true end end end ZO_PreHook("ZO_Dialogs_ShowDialog", ShowDialog_Hook) end local function HookLargeGroupDialog() local function ShowDialog_Hook(name, data) if name == "LARGE_GROUP_INVITE_WARNING" then if SV.largeGroupDialog then local characterOrDisplayName = data GroupInviteByName(characterOrDisplayName) ZO_Menu_SetLastCommandWasFromMenu(true) ZO_Alert(ALERT, nil, zo_strformat(GetString("SI_GROUPINVITERESPONSE", GROUP_INVITE_RESPONSE_INVITED), ZO_FormatUserFacingDisplayName(characterOrDisplayName))) return true end end end ZO_PreHook("ZO_Dialogs_ShowDialog", ShowDialog_Hook) end local function HookImproveDialog() local function ShowDialog_Hook(name, data) if name == "CONFIRM_IMPROVE_ITEM" then if SV.improveDialog then ImproveSmithingItem(data.bagId, data.slotIndex, data.boostersToApply) return true end end end ZO_PreHook("ZO_Dialogs_ShowDialog", ShowDialog_Hook) end local function HookMarketAnnouncement() if SCENE_MANAGER.scenes.marketAnnouncement then local function SetState_Hook(self, state, ...) if state == SCENE_SHOWING then if SV.marketAnnouncement then SCENE_MANAGER:ShowBaseScene() end return SV.marketAnnouncement end end ZO_PreHook(SCENE_MANAGER.scenes.marketAnnouncement, "SetState", SetState_Hook) end end local function HookCrownCratesSystem() if SV.crownCrate then CROWN_CRATE_KEYBOARD_SCENE:RegisterCallback("StateChange", function(oldState, newState) CROWN_CRATE_KEYBOARD_SCENE.sceneName = "crownCrateKeyboard" if newState == SCENE_SHOWING then SCENE_MANAGER:ShowBaseScene() end end) end end local function HookAcceptOfferedQuest(fromLAM) local original = INTERACTION.eventCallbacks[EVENT_QUEST_OFFERED] local masterWritReceived local function OnQuestOffered() if masterWritReceived then masterWritReceived = false else original() end end local function OnLootReceived(_,_, itemLink) if GetItemLinkItemType(itemLink) == ITEMTYPE_MASTER_WRIT then masterWritReceived = true end end if SV.dontAcceptWritQuest then INTERACTION.control:RegisterForEvent(EVENT_LOOT_RECEIVED, OnLootReceived) INTERACTION.control:AddFilterForEvent(EVENT_LOOT_RECEIVED, REGISTER_FILTER_BAG_ID, BAG_BACKPACK) INTERACTION.control:AddFilterForEvent(EVENT_LOOT_RECEIVED, REGISTER_FILTER_UNIT_TAG, "player") INTERACTION.control:UnregisterForEvent(EVENT_QUEST_OFFERED) INTERACTION.control:RegisterForEvent(EVENT_QUEST_OFFERED, OnQuestOffered) elseif fromLAM then INTERACTION.control:UnregisterForEvent(EVENT_QUEST_OFFERED) INTERACTION.control:UnregisterForEvent(EVENT_LOOT_RECEIVED) INTERACTION.control:RegisterForEvent(EVENT_QUEST_OFFERED, original) end end local function HookReportItemFromInventory() local function AddSlotActionHook(self, actionStringId) if SV.noReportOnItems and actionStringId == SI_ITEM_ACTION_REPORT_ITEM then return true end end ZO_PreHook(ZO_InventorySlotActions, "AddSlotAction", AddSlotActionHook) end local function RemovePinsFromMaps() local isCapitalWayshrine = { [62] = true, -- Daggerfall [56] = true, -- Wayrest [55] = true, -- Rivenspire [43] = true, -- Sentinel [33] = true, -- Bangkorai [121] = true, -- Auridon [214] = true, -- Grahtwood [143] = true, -- Greenshade [162] = true, -- Reapers [67] = true, -- Ebonheart [28] = true, -- Deshaan [48] = true, -- Shadowfen [109] = true, -- The Rift [87] = true, -- Eastmarch [251] = true, -- Gold Coast [252] = true, -- Gold Coast [220] = true, -- Belkarth [215] = true, -- Eyévéa [255] = true, -- Hew's Bane [244] = true, -- Orsinium [177] = true, -- Vulkheel [142] = true, -- Khenarthi [102] = true, -- Malabal Tor [106] = true, -- Malabal Tor [65] = true, -- Malabal Tor [138] = true, -- Stros M'Kai [181] = true, -- Betnikh [172] = true, -- Bleakrock } local isTrial = { [230] = true, -- Hel-Ra [232] = true, -- Aetherian Archive [232] = true, -- Sanctum Ophidia [250] = true, -- Maelstrom Arena [270] = true, -- DragonStar Arena } local unownedHouse = "/esoui/art/icons/poi/poi_group_house_unowned.dds" local ownedHouse = "/esoui/art/icons/poi/poi_group_house_owned.dds" local original = GetFastTravelNodeInfo GetFastTravelNodeInfo = function(nodeIndex, ...) local known, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked = original(nodeIndex, ...) if GetMapType() == MAPTYPE_WORLD then if SV.hideTamriel then -- Everything return false, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked end if SV.hideTamrielWayhsrines == 1 and poiType == POI_TYPE_WAYSHRINE and not isCapitalWayshrine[nodeIndex] then -- Capital Wayshrines return false, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked elseif SV.hideTamrielWayhsrines == 2 and poiType == POI_TYPE_WAYSHRINE then -- All Wayshrines return false, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked end if SV.hideTamrielDungeons == 1 and poiType == POI_TYPE_GROUP_DUNGEON and not isTrial[nodeIndex] then -- All Trial return false, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked elseif SV.hideTamrielDungeons == 2 and poiType == POI_TYPE_GROUP_DUNGEON then -- All Dungeons return false, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked end if SV.ownedHouses == 1 and poiType == POI_TYPE_HOUSE and icon == ownedHouse then return false, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked end if SV.unownedHouses == 1 and poiType == POI_TYPE_HOUSE and icon == unownedHouse then return false, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked end end if SV.ownedHouses == 2 and poiType == POI_TYPE_HOUSE and icon == ownedHouse then return false, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked end if SV.unownedHouses == 2 and poiType == POI_TYPE_HOUSE and icon == unownedHouse then return false, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked end return known, name, normalizedX, normalizedY, icon, glowIcon, poiType, isShownInCurrentMap, linkedCollectibleIsLocked end end local function HandleLuaErrorEvent() if SV.luaError == 1 then --unregister original handler EVENT_MANAGER:UnregisterForEvent("ErrorFrame", EVENT_LUA_ERROR) local seenBugs = {} --create a new event handler local function OnLuaError(_, errString) -- Display a notification local LNTF = LibStub("LibNotifications") local provider = LNTF:CreateProvider() local function RemoveNotification(data) table.remove(provider.notifications, data.notificationId) provider:UpdateNotifications() end if not seenBugs[errString] then local msg = { dataType = NOTIFICATIONS_REQUEST_DATA, secsSinceRequest = ZO_NormalizeSecondsSince(0), message = GetString(NOTYOU_LUAERR_MESSAGE), note = errString, heading = GetString(NOTYOU_LUAERR_HEADING), texture = "/esoui/art/miscellaneous/eso_icon_warning.dds", shortDisplayText = GetString(NOTYOU_LUAERR_SHORT), controlsOwnSounds = true, keyboardAcceptCallback = function(data) ZO_ERROR_FRAME:OnUIError(errString) RemoveNotification(data) end, keybaordDeclineCallback = RemoveNotification, gamepadAcceptCallback = function(data) ZO_ERROR_FRAME:OnUIError(errString) RemoveNotification(data) end, gamepadDeclineCallback = RemoveNotification, data = {errString = errString}, } table.insert(provider.notifications, msg) provider:UpdateNotifications() seenBugs[errString] = true end end EVENT_MANAGER:RegisterForEvent("LUA_ERROR", EVENT_LUA_ERROR, OnLuaError) end end local function HandleLuaLowMemoryEvent() --unregister original handler EVENT_MANAGER:UnregisterForEvent("ZO_UIErrors_OnEvent", EVENT_LUA_LOW_MEMORY) --define new dialog local lowMemoryDialog = { gamepadInfo = { dialogType = GAMEPAD_DIALOGS.BASIC }, title = { text = GetString(NOTYOU_LUADIALOG_TITLE) }, mainText = { text = GetString(NOTYOU_LUADIALOG_TEXT) }, buttons = { [1] = { text = SI_DIALOG_YES, callback = function(dialog) SetCVar("LuaMemoryLimitMB", tostring(dialog.data.newLimit)) ReloadUI("ingame") end, }, [2] = { text = SI_DIALOG_NO } } } ZO_Dialogs_RegisterCustomDialog("LUA_LOW_MEMORY", lowMemoryDialog) if SV.luaMemory == 0 then --create a new event handler local function OnEventNoDialog() --create a new event handler local function OnEventDialog(data) local currentLimit = tonumber(GetCVar("LuaMemoryLimitMB")) or 64 --round to the next power of two local _, exponent = math.frexp(currentLimit) local newLimit = 2 ^ exponent if not ZO_Dialogs_IsShowing("LUA_LOW_MEMORY") then if IsInGamepadPreferredMode() then ZO_Dialogs_ShowGamepadDialog("LUA_LOW_MEMORY", { newLimit = newLimit }, { mainTextParams = { currentLimit, newLimit } } ) else ZO_Dialogs_ShowDialog("LUA_LOW_MEMORY", { newLimit = newLimit }, { mainTextParams = { currentLimit, newLimit } } ) end end end -- Display a notification local LNTF = LibStub("LibNotifications") local provider = LNTF:CreateProvider() local function RemoveNotification(data) table.remove(provider.notifications, data.notificationId) provider:UpdateNotifications() end local msg = { dataType = NOTIFICATIONS_REQUEST_DATA, secsSinceRequest = ZO_NormalizeSecondsSince(0), message = GetString(NOTYOU_LUAMEM_MESSAGE), heading = GetString(NOTYOU_LUAMEM_HEADING), texture = "/esoui/art/miscellaneous/eso_icon_warning.dds", shortDisplayText = GetString(NOTYOU_LUAMEM_SHORT), controlsOwnSounds = true, keyboardAcceptCallback = OnEventDialog, keybaordDeclineCallback = RemoveNotification, gamepadAcceptCallback = OnEventDialog, gamepadDeclineCallback = RemoveNotification, data = {}, } table.insert(provider.notifications, msg) provider:UpdateNotifications() end EVENT_MANAGER:RegisterForEvent("LUA_LOW_MEMORY_DIALOG", EVENT_LUA_LOW_MEMORY, OnEventNoDialog) else -- Display the dialog directly --create a new event handler local function OnEventDialog() local currentLimit = tonumber(GetCVar("LuaMemoryLimitMB")) or 64 --round to the next power of two local _, exponent = math.frexp(currentLimit) local newLimit = 2 ^ exponent if not ZO_Dialogs_IsShowing("LUA_LOW_MEMORY") then if IsInGamepadPreferredMode() then ZO_Dialogs_ShowGamepadDialog("LUA_LOW_MEMORY", { newLimit = newLimit }, { mainTextParams = { currentLimit, newLimit } } ) else ZO_Dialogs_ShowDialog("LUA_LOW_MEMORY", { newLimit = newLimit }, { mainTextParams = { currentLimit, newLimit } } ) end end end EVENT_MANAGER:RegisterForEvent("LUA_LOW_MEMORY_DIALOG", EVENT_LUA_LOW_MEMORY, OnEventDialog) end end local function BuildSettingsMenu() local panelData = { type = "panel", name = "No, thank you!", author = ADDON_AUTHOR, version = ADDON_VERSION, slashCommand = "/noty", registerForRefresh = true, registerForDefaults = true, website = ADDON_WEBSITE, } local guildInvites = { GetString(NOTY_GUILD_INV_OPTION_0), GetString(NOTY_GUILD_INV_OPTION_1), GetString(NOTY_GUILD_INV_OPTION_2) } local guildInvitesLookup = { [GetString(NOTY_GUILD_INV_OPTION_0)] = 0, [GetString(NOTY_GUILD_INV_OPTION_1)] = 1, [GetString(NOTY_GUILD_INV_OPTION_2)] = 2 } local avaMode = { GetString(NOTY_AVA_MODE_OPTION_0), GetString(NOTY_AVA_MODE_OPTION_1), GetString(NOTY_AVA_MODE_OPTION_2) } local avaModeLookup = { [GetString(NOTY_AVA_MODE_OPTION_0)] = 0, [GetString(NOTY_AVA_MODE_OPTION_1)] = 1, [GetString(NOTY_AVA_MODE_OPTION_2)] = 2 } local loreLibraryMode = { GetString(NOTY_AVA_MODE_OPTION_0), GetString(NOTY_AVA_MODE_OPTION_1), GetString(NOTY_AVA_MODE_OPTION_2) } local loreLibraryModeLookup = { [GetString(NOTY_AVA_MODE_OPTION_0)] = 0, [GetString(NOTY_AVA_MODE_OPTION_1)] = 1, [GetString(NOTY_AVA_MODE_OPTION_2)] = 2 } local skillsProgressionMode = { GetString(NOTY_AVA_MODE_OPTION_0), GetString(NOTY_AVA_MODE_OPTION_1), GetString(NOTY_AVA_MODE_OPTION_2) } local skillsProgressionModeLookup = { [GetString(NOTY_AVA_MODE_OPTION_0)] = 0, [GetString(NOTY_AVA_MODE_OPTION_1)] = 1, [GetString(NOTY_AVA_MODE_OPTION_2)] = 2 } local groupZoneMode = { GetString(NOTY_AVA_MODE_OPTION_0), GetString(NOTY_AVA_MODE_OPTION_1), GetString(NOTY_AVA_MODE_OPTION_2) } local groupZoneModeLookup = { [GetString(NOTY_AVA_MODE_OPTION_0)] = 0, [GetString(NOTY_AVA_MODE_OPTION_1)] = 1, [GetString(NOTY_AVA_MODE_OPTION_2)] = 2 } local soundMode = { GetString(NOTY_SOUND_MODE_OPTION_0), GetString(NOTY_SOUND_MODE_OPTION_1), GetString(NOTY_SOUND_MODE_OPTION_2), GetString(NOTY_SOUND_MODE_OPTION_3) } local soundModeLookup = { [GetString(NOTY_SOUND_MODE_OPTION_0)] = 0, [GetString(NOTY_SOUND_MODE_OPTION_1)] = 1, [GetString(NOTY_SOUND_MODE_OPTION_2)] = 2, [GetString(NOTY_SOUND_MODE_OPTION_3)] = 3 } local guildAlertsMode = { GetString(NOTY_GALERTS_OPTION_0), GetString(NOTY_GALERTS_OPTION_1), GetString(NOTY_GALERTS_OPTION_2) } local guildAlertsModeLookup = { [GetString(NOTY_GALERTS_OPTION_0)] = 0, [GetString(NOTY_GALERTS_OPTION_1)] = 1, [GetString(NOTY_GALERTS_OPTION_2)] = 2 } local raidMode = { GetString(NOTY_RAID_OPTION_0), GetString(NOTY_RAID_OPTION_1), GetString(NOTY_RAID_OPTION_2), GetString(NOTY_RAID_OPTION_3) } local raidModeLookup = { [GetString(NOTY_RAID_OPTION_0)] = 0, [GetString(NOTY_RAID_OPTION_1)] = 1, [GetString(NOTY_RAID_OPTION_2)] = 2, [GetString(NOTY_RAID_OPTION_3)] = 3 } local motdMode = { GetString(NOTY_MOTD_OPTION_0), GetString(NOTY_MOTD_OPTION_1), GetString(NOTY_MOTD_OPTION_2) } local motdModeLookup = { [GetString(NOTY_MOTD_OPTION_0)] = 0, [GetString(NOTY_MOTD_OPTION_1)] = 1, [GetString(NOTY_MOTD_OPTION_2)] = 2 } local guildLeaveMode = { GetString(NOTY_GUILDLEAVE_OPTION_0), GetString(NOTY_GUILDLEAVE_OPTION_1), GetString(NOTY_GUILDLEAVE_OPTION_2) } local guildLeaveModeLookup = { [GetString(NOTY_GUILDLEAVE_OPTION_0)] = 0, [GetString(NOTY_GUILDLEAVE_OPTION_1)] = 1, [GetString(NOTY_GUILDLEAVE_OPTION_2)] = 2 } local luaMemory = { GetString(NOTY_LUAMEM_OPTION_0), GetString(NOTY_LUAMEM_OPTION_1) } local luaMemoryLookup = { [GetString(NOTY_LUAMEM_OPTION_0)] = 0, [GetString(NOTY_LUAMEM_OPTION_1)] = 1 } local luaError = { GetString(NOTY_LUAERR_OPTION_0), GetString(NOTY_LUAERR_OPTION_1) } local luaErrorLookup = { [GetString(NOTY_LUAERR_OPTION_0)] = 0, [GetString(NOTY_LUAERR_OPTION_1)] = 1 } local tamrielWayhsrines = { GetString(NOTY_WAYSHRINE_OPTION_0), GetString(NOTY_WAYSHRINE_OPTION_1), GetString(NOTY_WAYSHRINE_OPTION_2) } local tamrielWayhsrinesLookup = { [GetString(NOTY_WAYSHRINE_OPTION_0)] = 0, [GetString(NOTY_WAYSHRINE_OPTION_1)] = 1, [GetString(NOTY_WAYSHRINE_OPTION_2)] = 2 } local tamrielDungeons = { GetString(NOTY_DUNGEONS_OPTION_0), GetString(NOTY_DUNGEONS_OPTION_1), GetString(NOTY_DUNGEONS_OPTION_2) } local tamrielDungeonsLookup = { [GetString(NOTY_DUNGEONS_OPTION_0)] = 0, [GetString(NOTY_DUNGEONS_OPTION_1)] = 1, [GetString(NOTY_DUNGEONS_OPTION_2)] = 2 } local unownedHouses = { GetString(NOTY_UNOWNED_HOUSES_OPTION_0), GetString(NOTY_UNOWNED_HOUSES_OPTION_1), GetString(NOTY_UNOWNED_HOUSES_OPTION_2) } local unownedHousesLookup = { [GetString(NOTY_UNOWNED_HOUSES_OPTION_0)] = 0, [GetString(NOTY_UNOWNED_HOUSES_OPTION_1)] = 1, [GetString(NOTY_UNOWNED_HOUSES_OPTION_2)] = 2 } local ownedHouses = { GetString(NOTY_UNOWNED_HOUSES_OPTION_0), GetString(NOTY_UNOWNED_HOUSES_OPTION_1), GetString(NOTY_UNOWNED_HOUSES_OPTION_2) } local ownedHousesLookup = { [GetString(NOTY_UNOWNED_HOUSES_OPTION_0)] = 0, [GetString(NOTY_UNOWNED_HOUSES_OPTION_1)] = 1, [GetString(NOTY_UNOWNED_HOUSES_OPTION_2)] = 2 } local optionsData = { --AvA Messages { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_AVA_HEADER)), }, { type = "dropdown", name = GetString(NOTYOU_AVA), tooltip = GetString(NOTYOU_AVA_TOOLTIP), choices = avaMode, getFunc = function() return avaMode[SV.ava + 1] end, setFunc = function(value) SV.ava = avaModeLookup[value] end, default = avaMode[defaults.ava + 1], }, --Group Zone Messages { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_GROUPZONE_HEADER)), }, { type = "dropdown", name = GetString(NOTYOU_GROUPZONE), tooltip = GetString(NOTYOU_GROUPZONE_TOOLTIP), choices = groupZoneMode, getFunc = function() return groupZoneMode[SV.groupZone + 1] end, setFunc = function(value) SV.groupZone = avaModeLookup[value] end, default = groupZoneMode[defaults.groupZone + 1], }, --Friends Status Messages { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_FRIENDS_HEADER)), }, { type = "checkbox", name = GetString(NOTYOU_FRIENDS_ACTIVITY), tooltip = GetString(NOTYOU_FRIENDS_ACTIVITY_TOOLTIP), getFunc = function() return SV.friends end, setFunc = function(value) SV.friends = value end, default = defaults.friends, }, { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_TEXT_ALERTS_HEADER)), }, --Ability alerts { type = "checkbox", name = GetString(NOTYOU_MOB_IMMUNE), tooltip = GetString(NOTYOU_MOB_IMMUNE_TOOLTIP), getFunc = function() return SV.boss end, setFunc = function(value) SV.boss = value end, default = defaults.boss, }, --Screenshot Saved alert { type = "checkbox", name = GetString(NOTYOU_SCREENSHOT), tooltip = GetString(NOTYOU_SCREENSHOT_TOOLTIP), getFunc = function() return SV.screenshot end, setFunc = function(value) SV.screenshot = value end, default = defaults.screenshot, }, --Enlightened alert { type = "checkbox", name = GetString(NOTYOU_ENLIGHTENED), tooltip = GetString(NOTYOU_ENLIGHTENED_TOOLTIP), getFunc = function() return SV.enlightened end, setFunc = function(value) SV.enlightened = value end, default = defaults.enlightened, disabled = function() return not IsEnlightenedAvailableForCharacter() end, }, --Crafting Result alerts { type = "checkbox", name = GetString(NOTYOU_CRAFTRESULT), tooltip = GetString(NOTYOU_CRAFTRESULT_TOOLTIP), getFunc = function() return SV.craftingResults end, setFunc = function(value) SV.craftingResults = value end, default = defaults.craftingResults, }, --Repair alerts { type = "checkbox", name = GetString(NOTYOU_REPAIR), tooltip = GetString(NOTYOU_REPAIR_TOOLTIP), getFunc = function() return SV.repair end, setFunc = function(value) SV.repair = value end, default = defaults.repair, disabled = function() return ZO_GamepadStoreManager == nil end, }, --AlertText throttling { type = "slider", name = GetString(NOTYOU_ALERT_THROTTLING), tooltip = GetString(NOTYOU_ALERT_THROTTLING_TOOLTIP), min = 3, max = 30, getFunc = function() return SV.alertTextExpiryDelay end, setFunc = function(value) SV.alertTextExpiryDelay = value recentMessages.expiryDelayMilliseconds = value * 1000 end, default = defaults.alertTextExpiryDelay, }, { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_SOUND_HEADER)), }, { type = "dropdown", name = GetString(NOTYOU_ULTISOUND), tooltip = GetString(NOTYOU_ULTISOUND_TOOLTIP), choices = soundMode, getFunc = function() return soundMode[SV.ultimateSound + 1] end, setFunc = function(value) SV.ultimateSound = soundModeLookup[value] end, default = soundMode[defaults.ultimateSound + 1], }, --Hide market announcement { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(SI_GAMEPAD_MAIN_MENU_MARKET_ENTRY)), }, { type = "checkbox", name = GetString(NOTYOU_MARKET_ADS), tooltip = GetString(NOTYOU_MARKET_ADS_TOOLTIP), getFunc = function() return SV.marketAnnouncement end, setFunc = function(value) SV.marketAnnouncement = value end, default = defaults.marketAnnouncement, disabled = function() return SCENE_MANAGER.scenes.marketAnnouncement == nil end, }, { type = "checkbox", name = GetString(NOTYOU_CROWCRATES), tooltip = GetString(NOTYOU_CROWCRATES_TOOLTIP), getFunc = function() return SV.crownCrate end, setFunc = function(value) SV.crownCrate = value end, default = defaults.crownCrate, }, --Confirmation dialog when deleting empty mails { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_MAIL_HEADER)), }, { type = "checkbox", name = GetString(NOTYOU_MAIL), tooltip = GetString(NOTYOU_MAIL_TOOLTIP), getFunc = function() return SV.emptyMail end, setFunc = function(value) SV.emptyMail = value end, default = defaults.emptyMail, }, --Confirmation dialog when selling rare items to fence { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_FENCE_HEADER)), }, { type = "checkbox", name = GetString(NOTYOU_FENCE), tooltip = GetString(NOTYOU_FENCE_TOOLTIP), getFunc = function() return SV.fenceDialog end, setFunc = function(value) SV.fenceDialog = value end, default = defaults.fenceDialog, }, --Confirmation dialog when disband group and setting large group { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_GROUPS_HEADER)), }, { type = "checkbox", name = GetString(NOTYOU_GROUPS_DISBAND), tooltip = GetString(NOTYOU_GROUPS_DISBAND_TOOLTIP), getFunc = function() return SV.disbandDialog end, setFunc = function(value) SV.disbandDialog = value end, default = defaults.disbandDialog, }, { type = "checkbox", name = GetString(NOTYOU_GROUPS_LARGE), tooltip = GetString(NOTYOU_GROUPS_LARGE_TOOLTIP), getFunc = function() return SV.largeGroupDialog end, setFunc = function(value) SV.largeGroupDialog = value end, default = defaults.largeGroupDialog, }, --Confirmation dialog when crafting { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_CRAFT_HEADER)), }, { type = "checkbox", name = GetString(NOTYOU_CRAFT), tooltip = GetString(NOTYOU_CRAFT_TOOLTIP), getFunc = function() return SV.improveDialog end, setFunc = function(value) SV.improveDialog = value end, default = defaults.improveDialog, }, --Chameleon checkbox { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_CHAMELEON_HEADER)), }, { type = "checkbox", name = GetString(NOTYOU_CHAMELEON), tooltip = GetString(NOTYOU_CHAMELEON_TOOLTIP), getFunc = function() return SV.noUniversalStones end, setFunc = function(value) SV.noUniversalStones = value NoUniversalStones() end, default = defaults.noUniversalStones, }, -- Reticle options { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_RETICLE_HEADER)), }, { type = "checkbox", name = GetString(NOTYOU_RETICLE_TAKE), tooltip = GetString(NOTYOU_RETICLE_TAKE_TOOLTIP), getFunc = function() return SV.reticleTake end, setFunc = function(value) SV.reticleTake = value end, default = defaults.reticleTake, }, -- Auto Loot Items { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_AUTOLOOTITEMS_HEADER)), }, { type = "checkbox", name = GetString(NOTYOU_AUTOLOOTITEMS), tooltip = GetString(NOTYOU_AUTOLOOTITEMS_TOOLTIP), getFunc = function() return SV.autoLootItems end, setFunc = function(value) SV.autoLootItems = value NoLootWindowOnItems() end, default = defaults.autoLootItems, }, -- Guild Invites { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_GUILDS_HEADER)), }, { type = "dropdown", name = GetString(NOTYOU_GUILDS), tooltip = GetString(NOTYOU_GUILDS_TOOLTIP), choices = guildInvites, getFunc = function() return guildInvites[SV.guildInvites + 1] end, setFunc = function(value) SV.guildInvites = guildInvitesLookup[value] end, default = guildInvites[defaults.guildInvites + 1], }, { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_CAMERA_HEADER)), }, { type = "checkbox", name = GetString(NOTYOU_CAMERA_INTERRUPT), tooltip = GetString(NOTYOU_CAMERA_INTERRUPT_TOOLTIP), getFunc = function() return SV.nonstopHarvest end, setFunc = function(value) SV.nonstopHarvest = value end, default = defaults.nonstopHarvest, }, { type = "checkbox", name = GetString(NOTYOU_CAMERA_ROTATE), tooltip = GetString(NOTYOU_CAMERA_ROTATE_TOOLTIP), getFunc = function() return SV.noCameraSpin end, setFunc = function(value) SV.noCameraSpin = value DontRotateGameCamera() end, default = defaults.noCameraSpin, }, { -- Lore Library type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(SI_WINDOW_TITLE_LORE_LIBRARY)), }, { type = "checkbox", name = GetString(NOTYOU_NOLOREREADER), tooltip = GetString(NOTYOU_NOLOREREADER_TOOLTIP), getFunc = function() return SV.dontReadBooks end, setFunc = function(value) SV.dontReadBooks = value DontReadBooks() end, default = defaults.dontReadBooks, }, { type = "dropdown", name = GetString(NOTYOU_NOLOREDISCOVERIES), tooltip = GetString(NOTYOU_NOLOREDISCOVERIES_TOOLTIP), choices = loreLibraryMode, getFunc = function() return loreLibraryMode[SV.dontShowLoreDiscoveries + 1] end, setFunc = function(value) SV.dontShowLoreDiscoveries = loreLibraryModeLookup[value] end, default = loreLibraryMode[defaults.dontShowLoreDiscoveries + 1], }, { -- Crafting Bag type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(SI_NOTIFICATIONTYPE15)), }, { type = "checkbox", name = GetString(NOTYOU_NOCRAFTBAG_NOTIF), tooltip = GetString(NOTYOU_NOCRAFTBAG_NOTIF_TOOLTIP), getFunc = function() return SV.craftBag end, setFunc = function(value) SV.craftBag = value HookCraftBagNotifications() end, default = defaults.craftBag, }, { -- Skills type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(SI_WINDOW_TITLE_SKILLS)), }, { type = "dropdown", name = GetString(NOTYOU_NOSKILLSPROGRESS), tooltip = GetString(NOTYOU_NOSKILLSPROGRESS_TOOLTIP), choices = skillsProgressionMode, getFunc = function() return skillsProgressionMode[SV.dontShowSkillProgression + 1] end, setFunc = function(value) SV.dontShowSkillProgression = skillsProgressionModeLookup[value] end, default = skillsProgressionMode[defaults.dontShowSkillProgression + 1], }, { -- Inventory type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(zo_strformat(GetString(SI_MAIN_MENU_INVENTORY))), }, { type = "checkbox", name = GetString(NOTYOU_NOREPORTONITEMS), tooltip = GetString(NOTYOU_NOREPORTONITEMS_TOOLTIP), getFunc = function() return SV.noReportOnItems end, setFunc = function(value) SV.noReportOnItems = value end, default = defaults.noReportOnItems, }, { -- Map type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(SI_MAIN_MENU_MAP)), }, { type = "checkbox", name = GetString(NOTYOU_TAMRIEL), tooltip = GetString(NOTYOU_TAMRIEL_TOOLTIP), getFunc = function() return SV.hideTamriel end, setFunc = function(value) SV.hideTamriel = value end, default = defaults.hideTamriel, }, { type = "dropdown", name = GetString(NOTYOU_WAYSHRINES), tooltip = GetString(NOTYOU_WAYSHRINES_TOOLTIP), choices = tamrielWayhsrines, getFunc = function() return tamrielWayhsrines[SV.hideTamrielWayhsrines + 1] end, setFunc = function(value) SV.hideTamrielWayhsrines = tamrielWayhsrinesLookup[value] end, default = tamrielWayhsrines[defaults.hideTamrielWayhsrines + 1], disabled = function() return SV.hideTamriel end, }, { type = "dropdown", name = GetString(NOTYOU_DUNGEONS), tooltip = GetString(NOTYOU_DUNGEONS_TOOLTIP), choices = tamrielDungeons, getFunc = function() return tamrielDungeons[SV.hideTamrielDungeons + 1] end, setFunc = function(value) SV.hideTamrielDungeons = tamrielDungeonsLookup[value] end, default = tamrielDungeons[defaults.hideTamrielDungeons + 1], disabled = function() return SV.hideTamriel end, }, { type = "dropdown", name = GetString(NOTYOU_UNOWNED_HOUSES), tooltip = GetString(NOTYOU_UNOWNED_HOUSES_TOOLTIP), choices = unownedHouses, getFunc = function() return unownedHouses[SV.unownedHouses + 1] end, setFunc = function(value) SV.unownedHouses = unownedHousesLookup[value] end, default = unownedHouses[defaults.unownedHouses + 1], }, { type = "dropdown", name = GetString(NOTYOU_OWNED_HOUSES), tooltip = GetString(NOTYOU_OWNED_HOUSES_TOOLTIP), choices = ownedHouses, getFunc = function() return ownedHouses[SV.ownedHouses + 1] end, setFunc = function(value) SV.ownedHouses = ownedHousesLookup[value] end, default = ownedHouses[defaults.ownedHouses + 1], }, { -- Quests type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(zo_strformat(GetString(SI_JOURNAL_MENU_QUESTS))), }, { type = "checkbox", name = GetString(NOTYOU_NOWRITQUESTS), tooltip = GetString(NOTYOU_NOWRITQUESTS_TOOLTIP), getFunc = function() return SV.dontAcceptWritQuest end, setFunc = function(value) SV.dontAcceptWritQuest = value HookAcceptOfferedQuest(true) end, default = defaults.dontAcceptWritQuest, }, } --Guild Alerts local submenuGuildAlerts = { type = "submenu", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_GROSTER_HEADER)), tooltip = GetString(NOTYOU_GROSTER_HEADER_TOOLTIP), controls = { { type = "dropdown", name = GetString(NOTYOU_GROSTER), tooltip = GetString(NOTYOU_GROSTER_TOOLTIP), choices = guildAlertsMode, getFunc = function() return guildAlertsMode[SV.guildAlerts + 1] end, setFunc = function(value) SV.guildAlerts = guildAlertsModeLookup[value] end, default = guildAlertsMode[defaults.guildAlerts + 1], }, { type = "texture", image = "EsoUI/Art/Quest/questJournal_divider.dds", imageWidth = 510, imageHeight = 4, }, }, } --RaidScore Notifications local submenuRaidScore = { type = "submenu", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_RAIDSCORE_HEADER)), tooltip = GetString(NOTYOU_RAIDSCORE_HEADER_TOOLTIP), controls = { { type = "dropdown", name = GetString(NOTYOU_RAIDSCORE_ONLYFOR), tooltip = GetString(NOTYOU_RAIDSCORE_ONLYFOR_TOOLTIP), choices = raidMode, getFunc = function() return raidMode[SV.raid + 1] end, setFunc = function(value) SV.raid = raidModeLookup[value] end, default = raidMode[defaults.raid + 1], }, { type = "checkbox", name = GetString(NOTYOU_RAIDSCORE_REDIRECT), getFunc = function() return SV.raidToChat end, setFunc = function(value) SV.raidToChat = value end, default = defaults.raidToChat, disabled = function() return SV.raid == 3 end }, { type = "texture", image = "EsoUI/Art/Quest/questJournal_divider.dds", imageWidth = 510, imageHeight = 4, }, }, } --Guild MotD Notifications local submenuGuildMotD = { type = "submenu", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_MOTD_HEADER)), tooltip = GetString(NOTYOU_MOTD_HEADER_TOOLTIP), controls = { { type = "dropdown", name = GetString(NOTYOU_MOTD_BLOCK), tooltip = GetString(NOTYOU_MOTD_BLOCK_TOOLTIP), choices = motdMode, getFunc = function() return motdMode[SV.motd + 1] end, setFunc = function(value) SV.motd = motdModeLookup[value] end, default = motdMode[defaults.motd + 1], }, { type = "texture", image = "EsoUI/Art/Quest/questJournal_divider.dds", imageWidth = 510, imageHeight = 4, }, }, } -- NoGuildLeave Notifications local submenuGuildLeave = { type = "submenu", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_GUILDLEAVE_HEADER)), tooltip = GetString(NOTYOU_GUILDLEAVE_HEADER_TOOLTIP), controls = { { type = "dropdown", name = GetString(NOTYOU_GUILDLEAVE_BLOCK), tooltip = GetString(NOTYOU_GUILDLEAVE_BLOCK_TOOLTIP), choices = guildLeaveMode, getFunc = function() return guildLeaveMode[SV.noGuildLeave + 1] end, setFunc = function(value) SV.noGuildLeave = guildLeaveModeLookup[value] NoGuildLeave() end, default = guildLeaveMode[defaults.noGuildLeave + 1], }, { type = "texture", image = "EsoUI/Art/Quest/questJournal_divider.dds", imageWidth = 510, imageHeight = 4, }, }, } for i = 1, MAX_GUILDS do local gname = GetGuildName(GetGuildId(i)) --Guild Alerts local guildData = { type = "checkbox", name = (#gname > 0 and gname or "Guild " .. i), getFunc = function() return SV.guildAlertsGuilds[i] end, setFunc = function(value) SV.guildAlertsGuilds[i] = value NoGuildLeave() end, default = defaults.guildAlertsGuilds[i], disabled = function() return SV.guildAlerts == 0 end, } table.insert(submenuGuildAlerts.controls, guildData) --RaidScore Notifications guildData = { type = "checkbox", name = (#gname > 0 and gname or "Guild " .. i), getFunc = function() return SV.raidGuilds[i] end, setFunc = function(value) SV.raidGuilds[i] = value NOTIFICATIONS:RefreshNotificationList() end, default = defaults.raidGuilds[i], disabled = function() return SV.raid ~= 2 end, } table.insert(submenuRaidScore.controls, guildData) --Guild MotD Notifications local motdData = { type = "checkbox", name = (#gname > 0 and gname or "Guild " .. i), getFunc = function() return SV.motdGuilds[i] end, setFunc = function(value) SV.motdGuilds[i] = value NOTIFICATIONS:RefreshNotificationList() end, default = defaults.motdGuilds[i], disabled = function() return SV.motd == 0 end, } table.insert(submenuGuildMotD.controls, motdData) --Guild Leave local guildLeave = { type = "checkbox", name = (#gname > 0 and gname or "Guild " .. i), getFunc = function() return SV.guildLeave[i] end, setFunc = function(value) SV.guildLeave[i] = value end, default = defaults.guildLeave[i], disabled = function() return SV.noGuildLeave ~= 2 end, } table.insert(submenuGuildLeave.controls, guildLeave) end --add submenus to the optionsData table.insert(optionsData, submenuGuildAlerts) table.insert(optionsData, submenuRaidScore) table.insert(optionsData, submenuGuildMotD) table.insert(optionsData, submenuGuildLeave) table.insert(optionsData, { type = "header", name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(NOTYOU_LUA_HEADER)), }) table.insert(optionsData, { type = "dropdown", name = GetString(NOTYOU_LUA_MEMORY), tooltip = GetString(NOTYOU_LUA_MEMORY_TOOLTIP), choices = luaMemory, getFunc = function() return luaMemory[SV.luaMemory + 1] end, setFunc = function(value) SV.luaMemory = luaMemoryLookup[value] end, default = luaMemory[defaults.luaMemory + 1], }) table.insert(optionsData, { type = "dropdown", name = GetString(NOTYOU_LUA_ERROR), tooltip = GetString(NOTYOU_LUA_ERROR_TOOLTIP), choices = luaError, getFunc = function() return luaError[SV.luaError + 1] end, setFunc = function(value) SV.luaError = luaErrorLookup[value] HandleLuaErrorEvent() end, default = luaError[defaults.luaError + 1], }) local LAM = LibStub("LibAddonMenu-2.0") local panel = LAM:RegisterAddonPanel("NOTY_Panel", panelData) LAM:RegisterOptionControls("NOTY_Panel", optionsData) --add logo panel.logo = WINDOW_MANAGER:CreateControl(nil, panel, CT_TEXTURE) panel.logo:SetAnchor(TOP, panel, TOP, -5, 15) panel.logo:SetDimensions(420, 60) panel.logo:SetTexture("NoThankYou/Art/noty.dds") panel.logo:SetTextureCoords(0, 1, 0, 0.1429) panel.label:SetHeight(65) panel.label:SetHidden(true) panel.container:ClearAnchors() panel.container:SetAnchor(TOPLEFT, panel.info, BOTTOMLEFT, 0, 10) panel.container:SetAnchor(BOTTOMRIGHT, panel, BOTTOMRIGHT, -3, -3) end local function OnAddonLoaded(event, name) if name == ADDON_NAME then EVENT_MANAGER:UnregisterForEvent(ADDON_NAME, event) SV = ZO_SavedVars:NewAccountWide("NO_THANK_YOU_VARS", 1, defaults) --set hooks HookAvAMessages() HookGroupZoneMessages() HookFriendsMessages() BossAlertTextsHook() ScreenshotAlertHook() EnlightenedAlertHook() GuildRosterAlertsHook() CraftingResultAlertsHook() RepairAlertsHook() AlertTextThrottling() DeleteEmptyMailHook() HookRaidNotifications() HookMotDNotifications() HookCraftBagNotifications() HookReticleTake() HookGuildInvitesNotifications() HandleLuaErrorEvent() HandleLuaLowMemoryEvent() DontInterruptHarvesting() DontRotateGameCamera() HookFenceDialog() HookPlaySound() HookDisbandDialog() HookLargeGroupDialog() HookImproveDialog() HookMarketAnnouncement() HookCrownCratesSystem() HookPlayerToPlayerGuildInvite() DontReadBooks() DontShowLoreDiscoveries() DontShowSkillProgression() NoUniversalStones() NoGuildLeave() NoGuildLeavePreHook() NoLootWindowOnItems() HookReportItemFromInventory() RemovePinsFromMaps() BuildSettingsMenu() --rebuild notifications list NOTIFICATIONS:RefreshNotificationList() end end EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED, OnAddonLoaded)