From ad18f0845b61575730186fb5384029259958fa45 Mon Sep 17 00:00:00 2001 From: Lith77 <152820203+Lith77@users.noreply.github.com> Date: Fri, 6 Dec 2024 01:16:16 +0100 Subject: [PATCH] v1.0.5 Fix for Cataclysm mounts Added support for aquatic mounts, so if in water and you have a aquatic favorite mount that can be used in that area it will summon that, as long as you don't use the Flying or Ground specific slash command or keybind. --- LithStable.lua | 105 ++++++++++++++++++++++++++++++++++++++++++------- LithStable.toc | 2 +- changes.txt | 3 ++ debug.lua | 54 +++++++++++++++++++++++-- helper.lua | 33 +++++++++++++--- settings.lua | 42 +++++++++++++++++--- 6 files changed, 210 insertions(+), 29 deletions(-) diff --git a/LithStable.lua b/LithStable.lua index 9095c1a..d602f86 100644 --- a/LithStable.lua +++ b/LithStable.lua @@ -4,8 +4,10 @@ LithStable = LibStub("AceAddon-3.0"):NewAddon(LithStable, addonName, "AceConsole -- State variables LithStable.lastFlyingMount = nil LithStable.lastGroundMount = nil +LithStable.lastAquaticMount = nil LithStable.pendingMount = nil LithStable.pendingMountType = nil +--LithStable.aquaticMountBackup = false function LithStable:OnInitialize() -- Initialize settings @@ -14,6 +16,10 @@ function LithStable:OnInitialize() -- Load last mount states from character saved variables self.lastFlyingMount = self.db.char.state.lastFlyingMount self.lastGroundMount = self.db.char.state.lastGroundMount + self.lastAquaticMount = self.db.char.state.lastAquaticMount + + -- Initialize aquaticMountBackup + --self:UpdateAquaticMountBackup() -- Register slash commands self:RegisterChatCommand("ls", "HandleSlashCommand") @@ -39,8 +45,19 @@ function LithStable:OnInitialize() end end +--[[ +function LithStable:UpdateAquaticMountBackup() + if self.db.char.useSharedSettings then + self.aquaticMountBackup = self.db.profile.settings.aquaticBackup + else + self.aquaticMountBackup = self.db.char.settings.aquaticBackup + end +end]] + function LithStable:HandleSlashCommand(msg) - local command = string.lower(msg) + --local command = string.lower(msg) + local args = {strsplit(" ", msg)} + local command = string.lower(args[1] or "") if command == "help" then self:printHelp() elseif command == "debug" then @@ -52,14 +69,27 @@ function LithStable:HandleSlashCommand(msg) elseif command == "flying" then self:SummonRandomMount("flying", true) elseif command == "ground" then - self:SummonRandomMount("ground", true) + self:SummonRandomMount("ground", true) + elseif command == "debugam" then + if args[2] then + local mountID = tonumber(args[2]) + if mountID then + self:DebugPrintAnyMount(mountID) + else + print(format('|cFF8000FF%s|r|cffffffff%s|r %s', 'Lith', 'Stable:', "Invalid mount ID. Please provide a valid number.")) + end + else + print(format('|cFF8000FF%s|r|cffffffff%s|r %s', 'Lith', 'Stable:', "Usage: /ls debugam [mount_id]")) + end else self:SummonRandomMount(nil, false) end end + -- Main mount summoning function function LithStable:SummonRandomMount(rMountType, forceType) + if not self:CheckCooldown() then return end @@ -79,19 +109,24 @@ function LithStable:SummonRandomMount(rMountType, forceType) local favoriteMounts = { ground = {}, - flying = {} + flying = {}, + aquatic = {} } local canFly = self:CanFlyInCurrentZone() + local isSubmerged = IsSubmerged() + local isSwimming = IsSwimming() local unusableFavorites = {} - for i = 1, C_MountJournal.GetNumMounts() do - local name, spellID, icon, isActive, isUsable, sourceType, isFavorite, isFactionSpecific, faction, shouldHideOnChar, isCollected, mountID = C_MountJournal.GetMountInfoByID(i) - if mountID then + local name, spellID, icon, isActive, isUsable, sourceType, isFavorite, isFactionSpecific, faction, shouldHideOnChar, isCollected, mountID = C_MountJournal.GetMountInfoByID(C_MountJournal.GetDisplayedMountID(i)) + + if mountID and isCollected and isUsable then local localUsable, reason = C_MountJournal.GetMountUsabilityByID(mountID, false) if isCollected and isFavorite and not shouldHideOnChar then if isUsable and localUsable then if self:IsFlyingMount(mountID) then table.insert(favoriteMounts.flying, mountID) + elseif self:IsAquaticMount(mountID) then + table.insert(favoriteMounts.aquatic, mountID) else table.insert(favoriteMounts.ground, mountID) end @@ -109,9 +144,37 @@ function LithStable:SummonRandomMount(rMountType, forceType) end end + --print("isSubmerged:", isSubmerged) + --print("isSwimming:", isSwimming) + --print("canFly:", canFly) + --print("favoriteMounts.aquatic:", #favoriteMounts.aquatic) + --print("favoriteMounts.flying:", #favoriteMounts.flying) + --print("favoriteMounts.ground:", #favoriteMounts.ground) + --print("self.aquaticMountBackup:", self.aquaticMountBackup) + local mountList local isFlying = false - if rMountType == "flying" and (canFly or forceType) then + local isAquatic = false + + if (isSubmerged or isSwimming) and not forceType then + if #favoriteMounts.aquatic > 0 then + mountList = favoriteMounts.aquatic + isAquatic = true + --[[ removed because not all flying mounts can be summoned in water, and no way to know + elseif self.aquaticMountBackup and canFly and #favoriteMounts.flying > 0 then + mountList = favoriteMounts.flying + isFlying = true + print("flying") + elseif self.aquaticMountBackup and #favoriteMounts.ground > 0 then + mountList = favoriteMounts.ground + print("ground")]] + else + print(format('|cFF8000FF%s|r|cffffffff%s|r %s', 'Lith', 'Stable:', "No aquatic mounts available.")) + return + end + LithStable:SRM(mountList, isFlying, isAquatic); + return + elseif rMountType == "flying" and (canFly or forceType) then if #favoriteMounts.flying > 0 then mountList = favoriteMounts.flying isFlying = true @@ -119,8 +182,12 @@ function LithStable:SummonRandomMount(rMountType, forceType) mountList = favoriteMounts.ground print(format('|cFF8000FF%s|r|cffffffff%s|r %s', 'Lith', 'Stable:', "No flying mounts available. Summoning a ground mount instead")) end + LithStable:SRM(mountList, isFlying, isAquatic); + return elseif rMountType == "ground" or (rMountType ~= "flying" and not canFly and not forceType) then mountList = favoriteMounts.ground + LithStable:SRM(mountList, isFlying, isAquatic); + return else if canFly and #favoriteMounts.flying > 0 then mountList = favoriteMounts.flying @@ -128,26 +195,35 @@ function LithStable:SummonRandomMount(rMountType, forceType) else mountList = favoriteMounts.ground end + LithStable:SRM(mountList, isFlying, isAquatic); + return end +end +function LithStable:SRM(mountList, isFlying, isAquatic) if #mountList > 0 then local selectedMount, selectedIndex if isFlying then - selectedMount, selectedIndex = self:GetRandomMountExcludingLast(mountList, self:GetLastMount("flying"), true) + selectedMount, selectedIndex = self:GetRandomMountExcludingLast(mountList, self:GetLastMount("flying"), true, false) + elseif isAquatic then + selectedMount, selectedIndex = self:GetRandomMountExcludingLast(mountList, self:GetLastMount("aquatic"), false, true) else - selectedMount, selectedIndex = self:GetRandomMountExcludingLast(mountList, self:GetLastMount("ground"), false) + selectedMount, selectedIndex = self:GetRandomMountExcludingLast(mountList, self:GetLastMount("ground"), false, false) end local actualIsFlying = self:IsFlyingMount(selectedMount) + local actualIsAquatic = self:IsAquaticMount(selectedMount) self.pendingMount = selectedMount - self.pendingMountType = actualIsFlying and "flying" or "ground" - if selectedMount == self.lastFlyingMount or self.lastGroundMount then + self.pendingMountType = actualIsFlying and "flying" or (actualIsAquatic and "aquatic" or "ground") + + if selectedMount == self.lastFlyingMount or self.lastGroundMount or self.lastAquaticMount then C_Timer.After(0.3, function() C_MountJournal.SummonByID(selectedMount) end) return end + C_MountJournal.SummonByID(selectedMount) else print(format('|cFF8000FF%s|r|cffffffff%s|r %s', 'Lith', 'Stable:', "You have no suitable favorite mounts available.")) @@ -212,7 +288,7 @@ mountEventFrame:SetScript("OnEvent", function(self, event) end for i = 1, C_MountJournal.GetNumMounts() do - local _, _, _, _, _, _, isFavorite, _, _, _, _, mountID = C_MountJournal.GetMountInfoByID(i) + local _, _, _, _, _, _, isFavorite, _, _, _, _, mountID = C_MountJournal.GetMountInfoByID(C_MountJournal.GetDisplayedMountID(i)) if mountID then LithStable.db.char.favorites.mounts[mountID] = isFavorite or nil end @@ -221,7 +297,7 @@ mountEventFrame:SetScript("OnEvent", function(self, event) if IsMounted() and LithStable.pendingMount then local activeMount = nil for i = 1, C_MountJournal.GetNumMounts() do - local _, _, _, isActive, _, _, _, _, _, _, _, mountID = C_MountJournal.GetMountInfoByID(i) + local _, _, _, isActive, _, _, _, _, _, _, _, mountID = C_MountJournal.GetMountInfoByID(C_MountJournal.GetDisplayedMountID(i)) if isActive then activeMount = mountID break @@ -230,8 +306,9 @@ mountEventFrame:SetScript("OnEvent", function(self, event) if activeMount == LithStable.pendingMount then local isFlying = LithStable:IsFlyingMount(LithStable.pendingMount) + local isAquatic = LithStable:IsAquaticMount(LithStable.pendingMount) -- Always save to character specific state - LithStable:SetLastMount(isFlying and "flying" or "ground", LithStable.pendingMount) + LithStable:SetLastMount(isFlying and "flying" or isAquatic and "aquatic" or "ground", LithStable.pendingMount) end end diff --git a/LithStable.toc b/LithStable.toc index 18cf66b..c33a224 100644 --- a/LithStable.toc +++ b/LithStable.toc @@ -2,7 +2,7 @@ ## Title: |cFF8000FFLith|rStable ## Notes: For when choosing a mount is harder than downing Deathwing. Let RNG be your Dragon Soul! ## Author: Lith -## Version: 1.0.4 +## Version: 1.0.5 ## SavedVariables: LithStableDB # Libraries (embedded) diff --git a/changes.txt b/changes.txt index 6e85418..59b1f7c 100644 --- a/changes.txt +++ b/changes.txt @@ -1,4 +1,7 @@ LithStable, Summons a random favorite mount +V1.0.5: + - Fix for Cataclysm mounts + - Added support for aquatic mounts, so if in water and you have a aquatic favorite mount that can be used in that area it will summon that, as long as you don't use the Flying or Ground specific slash command or keybind. V1.0.4: - Added options that are saved shared or per character - Addon now keeps track of last used flying and ground mount. diff --git a/debug.lua b/debug.lua index 108a602..a55f90b 100644 --- a/debug.lua +++ b/debug.lua @@ -7,23 +7,26 @@ function LithStable:DebugPrintFavorites() local availableMounts = { ground = {}, - flying = {} + flying = {}, + aquatic = {} } local unusableFavorites = {} -- Use the same mount collection logic as in SummonRandomMount for i = 1, C_MountJournal.GetNumMounts() do - local name, spellID, _, isActive, isUsable, sourceType, isFavorite, isFactionSpecific, faction, shouldHideOnChar, isCollected, mountID = C_MountJournal.GetMountInfoByID(i) + local name, spellID, _, isActive, isUsable, sourceType, isFavorite, isFactionSpecific, faction, shouldHideOnChar, isCollected, mountID = C_MountJournal.GetMountInfoByID(C_MountJournal.GetDisplayedMountID(i)) if mountID then local localUsable, reason = C_MountJournal.GetMountUsabilityByID(mountID, false) if isCollected and isFavorite and not shouldHideOnChar then - local mountTypeStr = self:IsFlyingMount(mountID) and "Flying" or "Ground" + local mountTypeStr = self:IsFlyingMount(mountID) and "Flying" or (self:IsAquaticMount(mountID) and "Aquatic" or "Ground") if isUsable and localUsable then -- Add to available mounts list local statusStr = "Usable" print(string.format("%s (SpellID: %d): %s, %s", name, spellID, mountTypeStr, statusStr)) if self:IsFlyingMount(mountID) then table.insert(availableMounts.flying, name) + elseif self:IsAquaticMount(mountID) then + table.insert(availableMounts.aquatic, name) else table.insert(availableMounts.ground, name) end @@ -48,6 +51,11 @@ function LithStable:DebugPrintFavorites() if #availableMounts.ground > 0 then print(" " .. table.concat(availableMounts.ground, ", ")) end + + print("Available Aquatic Mounts:", #availableMounts.aquatic) + if #availableMounts.aquatic > 0 then + print(" " .. table.concat(availableMounts.aquatic, ", ")) + end if #unusableFavorites > 0 then print("Unusable Favorite Mounts:", #unusableFavorites) @@ -89,5 +97,45 @@ function LithStable:DebugPrintLastMounts() print("Last Ground Mount: None") end + -- Print last aquatic mount + if self.lastAquaticMount then + local name = C_MountJournal.GetMountInfoByID(self.lastAquaticMount) + if name then + local _, _, _, _, mountTypeID = C_MountJournal.GetMountInfoExtraByID(self.lastAquaticMount) + print(string.format("Last Aquatic Mount: %s (ID: %d, Type: %d)", name, self.lastAquaticMount, mountTypeID)) + end + else + print("Last Aquatic Mount: None") + end + print("---------------------------------------") end +function LithStable:DebugPrintAnyMount(spellID) + local mountID = C_MountJournal.GetMountFromSpell(spellID) + local name, spellID, icon, isActive, isUsable, sourceType, isFavorite, isFactionSpecific, faction, shouldHideOnChar, isCollected, realMountID = C_MountJournal.GetMountInfoByID(mountID) + local _, _, _, _, mountTypeID = C_MountJournal.GetMountInfoExtraByID(mountID) + local localUsable, reason = C_MountJournal.GetMountUsabilityByID(mountID, false) + print("---------------------------------------") + if name then + print(string.format("Mount Name: %s", name)) + print(string.format("Spell ID: %d", spellID)) + print(string.format("Icon: %s", icon)) + print(string.format("Is Active: %s", tostring(isActive))) + print(string.format("Is Usable: %s", tostring(isUsable))) + print(string.format("Is localUsable: %s", tostring(localUsable))) + if not localUsable then + print(string.format("Reason: %s", reason)) + end + print(string.format("Source Type: %s", sourceType)) + print(string.format("Is Favorite: %s", tostring(isFavorite))) + print(string.format("Is Faction Specific: %s", tostring(isFactionSpecific))) + print(string.format("Faction: %s", faction or "None")) + print(string.format("Should Hide on Character: %s", tostring(shouldHideOnChar))) + print(string.format("Is Collected: %s", tostring(isCollected))) + print(string.format("Mount ID: %d", realMountID)) + print(string.format("MountType ID: %d", mountTypeID)) + else + print(string.format("|cFF8000FF%s|r|cffffffff%s|r %s", 'Lith', 'Stable:', "No mount information available for the specified mount ID.")) + end + print("---------------------------------------") +end \ No newline at end of file diff --git a/helper.lua b/helper.lua index 5180038..5a56774 100644 --- a/helper.lua +++ b/helper.lua @@ -15,8 +15,15 @@ end -- Helper function to determine if a mount is a flying mount function LithStable:IsFlyingMount(mountID) local _, _, _, _, mountTypeID = C_MountJournal.GetMountInfoExtraByID(mountID) - -- 248 = Pure Flying, 247 = Flying/Ground, 407 = Dragonriding - return mountTypeID == 248 or mountTypeID == 247 or mountTypeID == 407 + -- 248 = Pure Flying, 247 = Flying/Ground, 402 = Dragonriding + return mountTypeID == 229 or mountTypeID == 238 or mountTypeID == 248 or mountTypeID == 247 or mountTypeID == 402 or mountTypeID == 436 +end + +-- Helper function to determine if a mount is a water mount +function LithStable:IsAquaticMount(mountID) + local _, _, _, _, mountTypeID = C_MountJournal.GetMountInfoExtraByID(mountID) + -- 231 = Ground and increased swim speed, 232 = Aquatic, can only be used in Vashj'ir, 254 = Aquatic only + return mountTypeID == 231 or mountTypeID == 232 or mountTypeID == 254 end -- Function to update spell cache @@ -84,7 +91,7 @@ function LithStable:GetTrueRandomIndex(max) end -- Random mount selection function -function LithStable:GetRandomMountExcludingLast(mountList, lastMount, isFlying) +function LithStable:GetRandomMountExcludingLast(mountList, lastMount, isFlying, isAquatic) -- Add debug prints to understand our lists --print("Mount list size:", #mountList) @@ -93,11 +100,14 @@ function LithStable:GetRandomMountExcludingLast(mountList, lastMount, isFlying) local availableFlying = 0 local availableGround = 0 + local availableAquatic = 0 -- Count mounts by type for _, mountID in ipairs(mountList) do if self:IsFlyingMount(mountID) then availableFlying = availableFlying + 1 + elseif self:IsAquaticMount(mountID) then + availableAquatic = availableAquatic + 1 else availableGround = availableGround + 1 end @@ -112,12 +122,21 @@ function LithStable:GetRandomMountExcludingLast(mountList, lastMount, isFlying) end end end + + -- If we're looking for an aquatic mount and only have one + if isAquatic and availableAquatic <= 1 then + for _, mountID in ipairs(mountList) do + if self:IsAquaticMount(mountID) then + return mountID, 1 + end + end + end -- If we're looking for a ground mount and only have one if not isFlying and availableGround <= 1 then -- Find and return the single ground mount for _, mountID in ipairs(mountList) do - if not self:IsFlyingMount(mountID) then + if not self:IsFlyingMount(mountID) and not self:IsAquaticMount(mountID) then return mountID, 1 end end @@ -184,6 +203,10 @@ function LithStable:SetLastMount(mountType, mountID) self.lastFlyingMount = mountID -- Always save to character state self.db.char.state.lastFlyingMount = mountID + elseif mountType == "aquatic" then + self.lastAquaticMount = mountID + -- Always save to character state + self.db.char.state.lastAquaticMount = mountID else self.lastGroundMount = mountID -- Always save to character state @@ -202,4 +225,4 @@ function LithStable:printHelp() print("|cFFFFFF00/ls|r", "Summons a mount by auto selectings") print("|cFFFFFF00/ls help|r", "Prints this list") print("---------------------------------------") -end \ No newline at end of file +end diff --git a/settings.lua b/settings.lua index 684e7bc..8b6291e 100644 --- a/settings.lua +++ b/settings.lua @@ -5,18 +5,21 @@ local defaults = { profile = { settings = { dismountOnly = false, - reoccurring = false + reoccurring = false, + aquaticBackup = false } }, char = { useSharedSettings = true, settings = { dismountOnly = false, - reoccurring = false + reoccurring = false, + aquaticBackup = false }, state = { lastFlyingMount = nil, - lastGroundMount = nil + lastGroundMount = nil, + lastAquaticMount = nil }, favorites = { mounts = {} @@ -146,9 +149,9 @@ function LithStable:InitializeSettings() dismountOnly = { type = "toggle", name = "If mounted just dismount", - desc = "If checked, using the mount command while mounted will only dismount without summoning a new mount", + desc = "If checked, using the mount command while mounted will only dismount without summoning a new mount.", width = "full", - order = 7, + order = 6.1, get = function() return self.db.char.useSharedSettings and self.db.profile.settings.dismountOnly @@ -162,6 +165,33 @@ function LithStable:InitializeSettings() end end, }, + --[[ --Removed because not all flying mounts can be summoned in water + aquaticDescription = { + type = "description", + name = "If checked, using the mount command while in water will fall back to summon a favorite flying or ground mount if no aquatic mount is available.", + order = 6.2, + fontSize = "medium", + }, + aquaticBackup = { + type = "toggle", + name = "Aquatic mount fallback", + desc = "If checked, using the mount command while in water will fall back to summon a favorite flying or ground mount if no aquatic mount is available.", + width = "full", + order = 6.3, + get = function() + return self.db.char.useSharedSettings + and self.db.profile.settings.aquaticBackup + or self.db.char.settings.aquaticBackup + end, + set = function(_, value) + if self.db.char.useSharedSettings then + self.db.profile.settings.aquaticBackup = value + else + self.db.char.settings.aquaticBackup = value + end + self:UpdateAquaticMountBackup() + end, + },]] spacer1 = { type = "description", name = " ", -- Empty spacer for layout alignment @@ -349,4 +379,4 @@ function LithStable:ShouldDismountOnly() return self.db.char.useSharedSettings and self.db.profile.settings.dismountOnly or self.db.char.settings.dismountOnly -end \ No newline at end of file +end