From ec868716ed7d0c5e2fd4b3f18946837e5dcb0d53 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Fri, 29 May 2026 15:43:42 +0200 Subject: [PATCH] coa.9: revert scale default + crash fixes + personal/realm bank + woodworking - Revert UIScale default 1.4->1.0 (scaling only zoomed, no extra content; real larger layout tracked separately). Apply saved scale on open, default 1.0. - Fix Options:Get/Set nil 'options' crash (TabOptions.lua:442). - Guild Members: guard Level_OnClick against cleared/stale row IDs. - Personal + Realm bank tracking ported from coa-bagnon (BANK_PERMISSIONS_PAYLOAD detection; personal per-char, realm per-realm; Search + BagUsage surfacing). - Woodcutting/Woodworking columns on Skills tab (CoA custom professions). --- Altoholic/Altoholic.lua | 12 +- Altoholic/Altoholic.toc | 2 +- Altoholic/Core.lua | 2 +- Altoholic/Frames/BagUsage.lua | 12 +- Altoholic/Frames/GuildMembers.lua | 2 + Altoholic/Frames/Search.lua | 40 ++- Altoholic/Frames/Skills.lua | 37 ++- Altoholic/Frames/Skills.xml | 22 +- Altoholic/Frames/TabOptions.lua | 4 +- Altoholic/Frames/TabOptions.xml | 10 +- DataStore_Containers/DataStore_Containers.lua | 281 +++++++++++++++++- DataStore_Containers/DataStore_Containers.toc | 2 +- DataStore_Skills/DataStore_Skills.lua | 20 ++ DataStore_Skills/DataStore_Skills.toc | 2 +- README.md | 1 + 15 files changed, 406 insertions(+), 43 deletions(-) diff --git a/Altoholic/Altoholic.lua b/Altoholic/Altoholic.lua index 95a09a9..437115d 100644 --- a/Altoholic/Altoholic.lua +++ b/Altoholic/Altoholic.lua @@ -404,15 +404,13 @@ end function addon:OnShow() SetPortraitTexture(AltoholicFramePortrait, "player"); - -- CoA: apply the saved UI scale on every open. Upstream only ran SetScale after the - -- Options tab was visited, so the window opened un-scaled. One-time bump of profiles - -- still on the old 1.0 default to the AtlasLoot-ish 1.4 default; a custom scale is kept. + -- CoA: apply the saved UI scale on open (upstream only applied it after the Options + -- tab was visited, so the window opened un-scaled). Default is 1.0 — scaling is opt-in + -- via Options; a true larger layout is tracked separately. local O = addon.db.global.options - if not O.coaScaleDefaulted then - O.coaScaleDefaulted = true - if (O.UIScale or 1.0) == 1.0 then O.UIScale = 1.4 end + if O and O.UIScale then + AltoholicFrame:SetScale(O.UIScale) end - AltoholicFrame:SetScale(O.UIScale or 1.4) addon.Characters:BuildList() addon.Characters:BuildView() diff --git a/Altoholic/Altoholic.toc b/Altoholic/Altoholic.toc index 8892d82..00f8720 100644 --- a/Altoholic/Altoholic.toc +++ b/Altoholic/Altoholic.toc @@ -13,7 +13,7 @@ ## Author: Thaoky, Telkar-RG ## X-Edited-By: Exiles (Sub-Net) — florian.berthold@sub-net.at -## Version: 3.3.002b-coa.8 +## Version: 3.3.002b-coa.9 ## X-Category: Inventory, Tradeskill, Mail ## X-Localizations: enUS, frFR, zhCN, zhTW, deDE, koKR, esES, esMX, ruRU ## X-Website: http://wow.curse.com/downloads/wow-addons/details/altoholic.aspx diff --git a/Altoholic/Core.lua b/Altoholic/Core.lua index 22b27b9..c08bfb9 100644 --- a/Altoholic/Core.lua +++ b/Altoholic/Core.lua @@ -85,7 +85,7 @@ local AddonDB_Defaults = { AccSharingHandlerEnabled = 0, -- account sharing communication handler is disabled by default GuildBankAutoUpdate = 0, -- can the guild bank tabs update requests be answered automatically or not. GuildHandlerEnabled = 1, -- guild communication handler is enabled by default - UIScale = 1.4, -- CoA: open at ~AtlasLoot footprint (832x447 * 1.4 = 1165x626 vs AtlasLoot 1105x640) + UIScale = 1.0, UITransparency = 1.0, ClampWindowToScreen = 0, diff --git a/Altoholic/Frames/BagUsage.lua b/Altoholic/Frames/BagUsage.lua index 6b038fb..ef6fc37 100644 --- a/Altoholic/Frames/BagUsage.lua +++ b/Altoholic/Frames/BagUsage.lua @@ -218,5 +218,15 @@ function ns:OnEnter(self) AltoTooltip:AddLine(" ",1,1,1); AltoTooltip:AddLine(CYAN .. numSlots .. " |r" .. L["slots"] .. " (" .. GREEN .. numFree .. "|r " ..L["free"] .. ") ",1,1,1); - AltoTooltip:Show(); + + -- CoA personal bank (per-character). Realm bank is per-realm, not per + -- character, so it is intentionally not shown on this character tooltip. + local personalTabs = DS:GetPersonalBankTabCount(character) or 0 + if personalTabs > 0 then + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(format("%sPersonal Bank|r: %s%d|r %s", + CYAN, WHITE, personalTabs, (personalTabs == 1) and "tab" or "tabs"), 1, 1, 1); + end + + AltoTooltip:Show(); end diff --git a/Altoholic/Frames/GuildMembers.lua b/Altoholic/Frames/GuildMembers.lua index 082e5df..c2cd9d9 100644 --- a/Altoholic/Frames/GuildMembers.lua +++ b/Altoholic/Frames/GuildMembers.lua @@ -460,7 +460,9 @@ function ns:Level_OnClick(self, button) if button ~= "LeftButton" then return end local id = self:GetParent():GetID() + if id == 0 then return end -- CoA: cleared/hidden rows keep SetID(0); view[0] is nil and indexing line.lineType below errors. Level_OnEnter & Collapse_OnClick already guard this; Level_OnClick (the AiL click that opens equipment) was the only handler missing it. local line = view[id] + if not line then return end -- CoA: stale button ID after a GUILD_ROSTER_UPDATE view rebuild can point past #view if line.lineType == NORMALPLAYER_LINE then return end local member = self:GetParent().CharName diff --git a/Altoholic/Frames/Search.lua b/Altoholic/Frames/Search.lua index 0e390c5..d4c7405 100644 --- a/Altoholic/Frames/Search.lua +++ b/Altoholic/Frames/Search.lua @@ -603,15 +603,17 @@ local function BrowseCharacter(character) currentResultLocation = L["Bank"] elseif (containerName == "Bag-2") then currentResultLocation = KEYRING + elseif string.sub(containerName, 1, 5) == "PBank" then -- CoA personal bank tab + currentResultLocation = "Personal Bank" else local bagNum = tonumber(string.sub(containerName, 4)) if (bagNum >= 0) and (bagNum <= 4) then currentResultLocation = L["Bags"] else currentResultLocation = L["Bank"] - end + end end - + for slotID = 1, container.size do itemID, itemLink, itemCount = DS:GetSlotInfo(container, slotID) @@ -710,7 +712,39 @@ local function BrowseRealm(realm, account, bothFactions) currentResultType = nil currentResultLocation = nil end - + + -- CoA realm bank: shared per-realm storage. Scanned once per realm (not per + -- character). Reported on the player-item line, attributed to the realm. + if addon.Options:Get("IncludeGuildBank") == 1 then + currentResultType = PLAYER_ITEM_LINE + -- Use the first scanned character of this realm as the row "source" so + -- the result lists the correct realm/account; if none, skip. + local anyChar + for _, character in pairs(DS:GetCharacters(realm, account)) do + anyChar = character + break + end + + if anyChar then + for tabID = 1, 6 do + local tab = DS:GetRealmBankTab(realm, account, tabID) + if tab and tab.name then + currentResultKey = anyChar + for slotID = 1, (tab.size or 0) do + currentResultLocation = format("Realm Bank (%s)", tab.name) + local id = tab.ids[slotID] + if id then + VerifyItem((tab.links or {})[slotID] or id, (tab.counts or {})[slotID] or 1) + end + end + end + end + currentResultKey = nil + end + currentResultType = nil + currentResultLocation = nil + end + if addon.Options:Get("IncludeGuildSkills") == 1 and string.len(currentValue) > 1 then -- Check guild professions ? local guild = addon:GetGuild() if guild and LTL then -- LTL won't be valid if there's a version mismatch (see :Init() ) diff --git a/Altoholic/Frames/Skills.lua b/Altoholic/Frames/Skills.lua index 90ca083..ae052bf 100644 --- a/Altoholic/Frames/Skills.lua +++ b/Altoholic/Frames/Skills.lua @@ -86,7 +86,9 @@ function ns:Update() _G[entry..i.."FirstAidNormalText"]:SetText("") _G[entry..i.."FishingNormalText"]:SetText("") _G[entry..i.."RidingNormalText"]:SetText("") - + _G[entry..i.."WoodcuttingNormalText"]:SetText("") + _G[entry..i.."WoodworkingNormalText"]:SetText("") + _G[ entry..i ]:SetID(line) _G[ entry..i ]:Show() i = i + 1 @@ -191,6 +193,20 @@ function ns:Update() end _G[entry..i.."RidingNormalText"]:SetText(icon .. ns:GetColor(field, 300) .. field) + + -- CoA custom professions: Woodcutting (spell 13977860) + Woodworking (spell 1005008). + -- Ranks are read live from DataStore_Skills' name-based getters (not from a + -- precomputed Characters field) so this stays self-contained. The getters return + -- 0 on non-CoA chars or chars not yet scanned; still guarded with "or 0" before + -- GetColor/concat. DataStore methods may be absent if DataStore_Skills is an older + -- build, so guard each call with an existence check. + field = (DS.GetWoodcuttingRank and (DS:GetWoodcuttingRank(character)) or 0) or 0 + icon = addon:TextureToFontstring2(addon:GetSpellIcon(13977860), size, size, inset, inset, inset, inset) .. " " + _G[entry..i.."WoodcuttingNormalText"]:SetText(icon .. ns:GetColor(field) .. field) + + field = (DS.GetWoodworkingRank and (DS:GetWoodworkingRank(character)) or 0) or 0 + icon = addon:TextureToFontstring2(addon:GetSpellIcon(1005008), size, size, inset, inset, inset, inset) .. " " + _G[entry..i.."WoodworkingNormalText"]:SetText(icon .. ns:GetColor(field) .. field) elseif (lineType == INFO_TOTAL_LINE) then _G[entry..i.."Collapse"]:Hide() _G[entry..i.."Name"]:SetWidth(200) @@ -204,6 +220,8 @@ function ns:Update() _G[entry..i.."FirstAidNormalText"]:SetText("") _G[entry..i.."FishingNormalText"]:SetText("") _G[entry..i.."RidingNormalText"]:SetText("") + _G[entry..i.."WoodcuttingNormalText"]:SetText("") + _G[entry..i.."WoodworkingNormalText"]:SetText("") end _G[ entry..i ]:SetID(line) _G[ entry..i ]:Show() @@ -245,6 +263,10 @@ function ns:OnEnter(frame) skillName = GetSpellInfo(24303) -- Fishing elseif id == 6 then skillName = L["Riding"] + elseif id == 8 then + skillName = GetSpellInfo(13977860) or "Woodcutting" -- CoA custom: Woodcutting + elseif id == 9 then + skillName = GetSpellInfo(1005008) or "Woodworking" -- CoA custom: Woodworking end local DS = DataStore @@ -252,8 +274,11 @@ function ns:OnEnter(frame) local curRank, maxRank = DS:GetSkillInfo(character, skillName) curRank, maxRank = curRank or 0, maxRank or 0 -- CoA: getter returns no value for skills DataStore_Skills hasn't scanned local profession = DS:GetProfession(character, skillName) - - if (id >= 1) and (id <= 6) then + + if (id == 8) or (id == 9) then -- CoA custom professions: show rank + recipe summary like the primary professions + rank = ns:GetColor(curRank) .. curRank .. "/" .. maxRank + suggestion = addon:GetSuggestion(skillName, curRank) + elseif (id >= 1) and (id <= 6) then if id == 6 then -- riding rank = ns:GetColor(curRank, 300) .. curRank .. "/" .. maxRank else @@ -278,7 +303,7 @@ function ns:OnEnter(frame) AltoTooltip:AddLine(skillName,1,1,1); AltoTooltip:AddLine(GREEN..rank,1,1,1); - if id <= 4 then -- all skills except fishing & riding + if (id <= 4) or (id == 9) then -- crafting skills (incl. CoA Woodworking, id 9); skips fishing/riding/Woodcutting if skillName ~= GetSpellInfo(13614) and skillName ~= GetSpellInfo(8613) then -- no display for herbalism & skinning AltoTooltip:AddLine(" "); @@ -363,6 +388,10 @@ function ns:OnClick(frame, button) skillName = GetSpellInfo(2550) -- cooking elseif id == 4 then skillName = GetSpellInfo(3273) -- First Aid + elseif id == 8 then + skillName = GetSpellInfo(13977860) or "Woodcutting" -- CoA custom (gathering, no recipes) + elseif id == 9 then + skillName = GetSpellInfo(1005008) or "Woodworking" -- CoA custom (crafting) end local DS = DataStore diff --git a/Altoholic/Frames/Skills.xml b/Altoholic/Frames/Skills.xml index 96a4a35..34a5186 100644 --- a/Altoholic/Frames/Skills.xml +++ b/Altoholic/Frames/Skills.xml @@ -34,7 +34,7 @@ + + - + diff --git a/Altoholic/Frames/TabOptions.lua b/Altoholic/Frames/TabOptions.lua index da988db..d1f14af 100644 --- a/Altoholic/Frames/TabOptions.lua +++ b/Altoholic/Frames/TabOptions.lua @@ -432,13 +432,13 @@ function Altoholic:MoveMinimapIcon() end function Altoholic.Options:Get(name) - if addon.db and addon.db.global then + if addon.db and addon.db.global and addon.db.global.options then return addon.db.global.options[name] end end function Altoholic.Options:Set(name, value) - if addon.db and addon.db.global then + if addon.db and addon.db.global and addon.db.global.options then addon.db.global.options[name] = value end end diff --git a/Altoholic/Frames/TabOptions.xml b/Altoholic/Frames/TabOptions.xml index a7b54d4..e0b4e5c 100644 --- a/Altoholic/Frames/TabOptions.xml +++ b/Altoholic/Frames/TabOptions.xml @@ -161,7 +161,7 @@ - + @@ -199,10 +199,10 @@ local name = self:GetParent():GetName() - _G[name .. "_SliderScale"]:SetValue(1.4) - _G[name .. "_SliderScaleText"]:SetText(format("%s (%1.1f)", UI_SCALE, 1.4)); - AltoholicFrame:SetScale(1.4) - Altoholic.Options:Set("UIScale", 1.4) + _G[name .. "_SliderScale"]:SetValue(1.0) + _G[name .. "_SliderScaleText"]:SetText(format("%s (%1.1f)", UI_SCALE, 1.0)); + AltoholicFrame:SetScale(1.0) + Altoholic.Options:Set("UIScale", 1.0) diff --git a/DataStore_Containers/DataStore_Containers.lua b/DataStore_Containers/DataStore_Containers.lua index 1472ca5..37cd2ad 100644 --- a/DataStore_Containers/DataStore_Containers.lua +++ b/DataStore_Containers/DataStore_Containers.lua @@ -35,6 +35,24 @@ local MSG_BANKTAB_TRANSFER = 6 -- .. or send the data local AddonDB_Defaults = { global = { + -- CoA (Ascension) Realm Bank: shared per-realm storage, keyed by "Account.Realm" + -- (NOT per-character). Mirrors the guild bank's Tabs layout so the same + -- scan/read helpers can be reused. + RealmBanks = { + ['*'] = { -- ["Account.Realm"] + lastUpdate = nil, + Tabs = { + ['*'] = { -- tabID = table index [1] to [6] + name = nil, + icon = nil, + size = 0, + ids = {}, + links = {}, + counts = {} + } + }, + } + }, Guilds = { ['*'] = { -- ["Account.Realm.Name"] money = nil, @@ -204,6 +222,16 @@ end local BAGS = 1 -- All bags, 0 to 11, and keyring ( id -2 ) local BANK = 2 -- 28 main slots local GUILDBANK = 3 -- 98 main slots +local PERSONALBANK = 4 -- CoA personal bank (per-character), read via guild bank API +local REALMBANK = 5 -- CoA realm bank (per-realm), read via guild bank API + +-- CoA reuses the Guild Bank UI for the Personal Bank and the Realm Bank. +-- These container key prefixes keep their scanned tabs out of the regular +-- "Bag0".."Bag11" / "Bag100" / "Bag-2" namespace so item-count loops can tell +-- them apart. Personal bank tabs live under the character; realm bank tabs live +-- in the realm-keyed global table. +local PERSONALBANK_PREFIX = "PBank" -- char.Containers["PBank1".."PBank6"] +local MAX_BANK_TABS = 6 local ContainerTypes = { [BAGS] = { @@ -262,9 +290,81 @@ local ContainerTypes = { GetCooldown = function(self, slotID) return nil end, + }, + -- Personal & Realm banks are read through the guild bank API (CoA reuses that UI). + [PERSONALBANK] = { + GetSize = function(self) + return MAX_GUILDBANK_SLOTS_PER_TAB or 98 + end, + GetFreeSlots = function(self) + return nil, nil + end, + GetLink = function(self, slotID, tabID) + return GetGuildBankItemLink(tabID, slotID) + end, + GetCount = function(self, slotID, tabID) + local _, count = GetGuildBankItemInfo(tabID, slotID) + return count + end, + GetCooldown = function(self, slotID) + return nil + end, + }, + [REALMBANK] = { + GetSize = function(self) + return MAX_GUILDBANK_SLOTS_PER_TAB or 98 + end, + GetFreeSlots = function(self) + return nil, nil + end, + GetLink = function(self, slotID, tabID) + return GetGuildBankItemLink(tabID, slotID) + end, + GetCount = function(self, slotID, tabID) + local _, count = GetGuildBankItemInfo(tabID, slotID) + return count + end, + GetCooldown = function(self, slotID) + return nil + end, } } +-- *** CoA bank-type detection *** +-- CoA exposes BANK_PERMISSIONS_PAYLOAD via the client-only HasJsonCacheData / +-- GetJsonCacheData / C_Serialize APIs. Guard every call so this is harmless on +-- non-CoA clients (where the personal/realm bank simply never triggers). +local function GetCoABankType() + if not (HasJsonCacheData and GetJsonCacheData and C_Serialize and C_Serialize.FromJSON) then + return "guild" + end + if not HasJsonCacheData("BANK_PERMISSIONS_PAYLOAD", 0) then + return "guild" + end + local json = GetJsonCacheData("BANK_PERMISSIONS_PAYLOAD", 0) + if not json then + return "guild" + end + local jsonObject = C_Serialize:FromJSON(json) + if not jsonObject then + return "guild" + end + if jsonObject.IsPersonalBank then + return "personal" + elseif jsonObject.IsRealmBank then + return "realm" + end + return "guild" +end + +local function GetRealmBankKey() + return format("%s.%s", THIS_ACCOUNT, GetRealmName()) +end + +local function GetThisRealmBank() + return addon.db.global.RealmBanks[GetRealmBankKey()] +end + -- *** Scanning functions *** local function ScanContainer(bagID, containerType) local Container = ContainerTypes[containerType] @@ -273,8 +373,15 @@ local function ScanContainer(bagID, containerType) if containerType == GUILDBANK then local thisGuild = GetThisGuild() if not thisGuild then return end - + bag = thisGuild.Tabs[bagID] -- bag is actually the current tab + elseif containerType == PERSONALBANK then + -- per-character storage, keyed by a tab-specific prefix so it never + -- collides with the normal bag/bank containers + bag = addon.ThisCharacter.Containers[PERSONALBANK_PREFIX .. bagID] + elseif containerType == REALMBANK then + local realmBank = GetThisRealmBank() + bag = realmBank.Tabs[bagID] -- bag is the current tab in the realm-keyed table else bag = addon.ThisCharacter.Containers["Bag" .. bagID] wipe(bag.cooldowns) -- does not exist for a guild bank @@ -315,8 +422,14 @@ local function ScanContainer(bagID, containerType) bag.cooldowns[index] = startTime .."|".. duration .. "|" .. 1 end end - - addon.ThisCharacter.lastUpdate = time() + + if containerType == REALMBANK then + GetThisRealmBank().lastUpdate = time() + else + -- personal bank, bags, bank and guild bank all stamp the character; + -- this is what gates DataStore's "no value" guard for char-based getters + addon.ThisCharacter.lastUpdate = time() + end end local function ScanBagSlotsInfo() @@ -463,25 +576,76 @@ local function OnBankFrameOpened() addon:RegisterEvent("PLAYERBANKSLOTS_CHANGED", OnPlayerBankSlotsChanged) end +-- Records the name/icon of a personal-bank tab. Reuses the per-character +-- container created by ScanContainer (PERSONALBANK_PREFIX .. tabID). +local function ScanPersonalBankInfo(tabID) + local bag = addon.ThisCharacter.Containers[PERSONALBANK_PREFIX .. tabID] + bag.name, bag.icon = GetGuildBankTabInfo(tabID) +end + +local function ScanRealmBankInfo(tabID) + local t = GetThisRealmBank().Tabs[tabID] + t.name, t.icon = GetGuildBankTabInfo(tabID) +end + local function OnGuildBankFrameClosed() addon:UnregisterEvent("GUILDBANKFRAME_CLOSED") addon:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED") - - local guildName = GetGuildInfo("player") - if guildName then - GuildBroadcast(MSG_SEND_BANK_TIMESTAMPS, GetBankTimestamps(guildName)) + + -- only broadcast guild bank timestamps for the actual guild bank + if addon.coaBankType == "guild" then + local guildName = GetGuildInfo("player") + if guildName then + GuildBroadcast(MSG_SEND_BANK_TIMESTAMPS, GetBankTimestamps(guildName)) + end end + + addon.coaBankType = nil + addon.coaBankAvailableTabs = nil end local function OnGuildBankBagSlotsChanged() - ScanContainer(GetCurrentGuildBankTab(), GUILDBANK) - ScanGuildBankInfo() + local currentTab = GetCurrentGuildBankTab() + + if addon.coaBankType == "personal" then + ScanContainer(currentTab, PERSONALBANK) + ScanPersonalBankInfo(currentTab) + elseif addon.coaBankType == "realm" then + ScanContainer(currentTab, REALMBANK) + ScanRealmBankInfo(currentTab) + else + -- regular guild bank, unchanged behaviour + ScanContainer(currentTab, GUILDBANK) + ScanGuildBankInfo() + end end local function OnGuildBankFrameOpened() + -- CoA reuses the guild bank UI for the personal & realm banks; detect which + -- one this is BEFORE doing anything guild-specific. Harmless ("guild") when + -- the CoA JSON APIs are absent. + addon.coaBankType = GetCoABankType() + addon:RegisterEvent("GUILDBANKFRAME_CLOSED", OnGuildBankFrameClosed) addon:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED", OnGuildBankBagSlotsChanged) - + + if addon.coaBankType == "personal" or addon.coaBankType == "realm" then + -- Pre-query the other tabs so we snapshot the whole bank without the + -- player having to click each tab. Each QueryGuildBankTab triggers a + -- GUILDBANKBAGSLOTS_CHANGED for that tab, handled above. + if QueryGuildBankTab then + local currentTab = GetCurrentGuildBankTab and GetCurrentGuildBankTab() or 0 + for tabID = 1, MAX_BANK_TABS do + local avail = GetGuildBankTabInfo(tabID) + if type(avail) == "string" and tabID ~= currentTab then + QueryGuildBankTab(tabID) + end + end + end + return + end + + -- regular guild bank local thisGuild = GetThisGuild() if thisGuild then thisGuild.money = GetGuildBankMoney() @@ -550,19 +714,22 @@ end local function _GetContainerItemCount(character, searchedID) local bagCount = 0 local bankCount = 0 + local personalBankCount = 0 local id - + for containerName, container in pairs(character.Containers) do for slotID=1, container.size do id = container.ids[slotID] - + if (id) and (id == searchedID) then local itemCount = container.counts[slotID] or 1 - + if (containerName == "Bag100") then bankCount = bankCount + itemCount elseif (containerName == "Bag-2") then bagCount = bagCount + itemCount + elseif string.sub(containerName, 1, #PERSONALBANK_PREFIX) == PERSONALBANK_PREFIX then + personalBankCount = personalBankCount + itemCount -- CoA personal bank tab else local bagNum = tonumber(string.sub(containerName, 4)) if (bagNum >= 0) and (bagNum <= 4) then @@ -575,7 +742,79 @@ local function _GetContainerItemCount(character, searchedID) end end - return bagCount, bankCount + -- 3rd return value (personal bank) is additive and backward-compatible: + -- existing callers that expect (bags, bank) just ignore it. + return bagCount, bankCount, personalBankCount +end + +-- *** CoA personal bank (per-character) *** +local function _GetPersonalBankItemCount(character, searchedID) + local count = 0 + for containerName, container in pairs(character.Containers) do + if string.sub(containerName, 1, #PERSONALBANK_PREFIX) == PERSONALBANK_PREFIX then + for slotID = 1, container.size do + if container.ids[slotID] == searchedID then + count = count + (container.counts[slotID] or 1) + end + end + end + end + return count +end + +local function _GetPersonalBankTabCount(character) + -- number of personal bank tabs that have been scanned (have a size) + local n = 0 + for tabID = 1, MAX_BANK_TABS do + local container = character.Containers[PERSONALBANK_PREFIX .. tabID] + if container and (container.size or 0) > 0 then + n = n + 1 + end + end + return n +end + +-- *** CoA realm bank (per-realm, NOT char-based) *** +-- These take a realm key string ("Account.Realm") directly and read the global +-- RealmBanks table, so they bypass DataStore's char/guild "no value" wrapper. +local function _GetRealmBankKey(realm, account) + realm = realm or GetRealmName() + account = account or THIS_ACCOUNT + return format("%s.%s", account, realm) +end + +local function _GetRealmBank(realm, account) + return addon.db.global.RealmBanks[_GetRealmBankKey(realm, account)] +end + +local function _GetRealmBankItemCount(realm, account, searchedID) + local realmBank = _GetRealmBank(realm, account) + if not realmBank then return 0 end + + local count = 0 + for _, tab in pairs(realmBank.Tabs) do + for slotID, id in pairs(tab.ids) do + if id == searchedID then + count = count + (tab.counts[slotID] or 1) + end + end + end + return count +end + +local function _GetRealmBankTab(realm, account, tabID) + local realmBank = _GetRealmBank(realm, account) + return realmBank and realmBank.Tabs[tabID] +end + +local function _GetRealmBankTabName(realm, account, tabID) + local tab = _GetRealmBankTab(realm, account, tabID) + return tab and tab.name +end + +local function _GetRealmBankLastUpdate(realm, account) + local realmBank = _GetRealmBank(realm, account) + return realmBank and realmBank.lastUpdate end local function _GetNumBagSlots(character) @@ -721,6 +960,14 @@ local PublicMethods = { RejectBankTabRequest = _RejectBankTabRequest, SendBankTabToGuildMember = _SendBankTabToGuildMember, GetGuildBankTabSuppliers = _GetGuildBankTabSuppliers, + -- CoA personal bank (per-character) + GetPersonalBankItemCount = _GetPersonalBankItemCount, + GetPersonalBankTabCount = _GetPersonalBankTabCount, + -- CoA realm bank (per-realm; takes realm/account, not a character/guild key) + GetRealmBankItemCount = _GetRealmBankItemCount, + GetRealmBankTab = _GetRealmBankTab, + GetRealmBankTabName = _GetRealmBankTabName, + GetRealmBankLastUpdate = _GetRealmBankLastUpdate, } -- *** Guild Comm *** @@ -809,7 +1056,11 @@ function addon:OnInitialize() DataStore:SetCharacterBasedMethod("GetNumFreeBagSlots") DataStore:SetCharacterBasedMethod("GetNumBankSlots") DataStore:SetCharacterBasedMethod("GetNumFreeBankSlots") - + DataStore:SetCharacterBasedMethod("GetPersonalBankItemCount") + DataStore:SetCharacterBasedMethod("GetPersonalBankTabCount") + -- Realm bank methods are intentionally NOT char/guild based: they take a + -- realm/account string pair directly and read the realm-keyed global table. + DataStore:SetGuildBasedMethod("GetGuildBankItemCount") DataStore:SetGuildBasedMethod("GetGuildBankTab") DataStore:SetGuildBasedMethod("GetGuildBankTabName") diff --git a/DataStore_Containers/DataStore_Containers.toc b/DataStore_Containers/DataStore_Containers.toc index e5ed9f0..56840ba 100644 --- a/DataStore_Containers/DataStore_Containers.toc +++ b/DataStore_Containers/DataStore_Containers.toc @@ -2,7 +2,7 @@ ## Title: DataStore_Containers ## Notes: Stores information about character bags, bank, and guild banks ## Author: Thaoky (EU-Marécages de Zangar) -## Version: 3.3.001 +## Version: 3.3.001-coa.9 ## Dependencies: DataStore ## OptionalDeps: Ace3 ## SavedVariables: DataStore_ContainersDB diff --git a/DataStore_Skills/DataStore_Skills.lua b/DataStore_Skills/DataStore_Skills.lua index 9ba2272..eb6ed69 100644 --- a/DataStore_Skills/DataStore_Skills.lua +++ b/DataStore_Skills/DataStore_Skills.lua @@ -77,6 +77,22 @@ local function _GetRidingRank(character) return _GetSkillInfoByCategory(character, L["Secondary Skills"], L["Riding"]) end + -- CoA (Ascension Vol'jin) adds two custom professions on top of the vanilla 15: + -- Woodcutting (gathering, base spell 13977860) and Woodworking (crafting, + -- ranks 1005008-1005011). They register as normal skill lines in the in-game + -- skill UI under their English names "Woodcutting" / "Woodworking" (confirmed + -- against coa-professionmenu, which reads them via GetSkillLineInfo by name). + -- ScanSkills() already buckets them by whatever category header they sit under, + -- so a name-based lookup across all categories retrieves them regardless of the + -- header. On non-CoA realms the skill simply doesn't exist and these return 0, 0. +local function _GetWoodcuttingRank(character) + return _GetSkillInfo(character, "Woodcutting") +end + +local function _GetWoodworkingRank(character) + return _GetSkillInfo(character, "Woodworking") +end + local PublicMethods = { GetPrimaryProfessions = _GetPrimaryProfessions, GetSecondaryProfessions = _GetSecondaryProfessions, @@ -86,6 +102,8 @@ local PublicMethods = { GetCookingRank = _GetCookingRank, GetFishingRank = _GetFishingRank, GetRidingRank = _GetRidingRank, + GetWoodcuttingRank = _GetWoodcuttingRank, + GetWoodworkingRank = _GetWoodworkingRank, } function addon:OnInitialize() @@ -100,6 +118,8 @@ function addon:OnInitialize() DataStore:SetCharacterBasedMethod("GetCookingRank") DataStore:SetCharacterBasedMethod("GetFishingRank") DataStore:SetCharacterBasedMethod("GetRidingRank") + DataStore:SetCharacterBasedMethod("GetWoodcuttingRank") + DataStore:SetCharacterBasedMethod("GetWoodworkingRank") end function addon:OnEnable() diff --git a/DataStore_Skills/DataStore_Skills.toc b/DataStore_Skills/DataStore_Skills.toc index f45dccb..21ec2ca 100644 --- a/DataStore_Skills/DataStore_Skills.toc +++ b/DataStore_Skills/DataStore_Skills.toc @@ -2,7 +2,7 @@ ## Title: DataStore_Skills ## Notes: Stores information about character skills ## Author: Thaoky (EU-Marécages de Zangar) -## Version: 3.3.002 +## Version: 3.3.002-coa.9 ## Dependencies: DataStore ## OptionalDeps: Ace3 ## SavedVariables: DataStore_SkillsDB diff --git a/README.md b/README.md index 0bafb55..7c1ad90 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Altoholic: modified development for WotLK Ported for the Ascension CoA (Vol'jin) 3.3.5a client by the Exiles guild. Released as `*-coa.N` tags via Gitea Actions; see `Exiles/coa-altoholic`. +- **3.3.002b-coa.9** — Reverted the 1.4 default scale (it only zoomed, didn't show more content; scale stays user-opt-in at 1.0 default, applied on open). Hardened `Options:Get/Set` against a nil `options` table (`TabOptions.lua:442` crash). Guild Members: guard `Level_OnClick` against cleared/stale row IDs (clicking AiL crashed). **New:** Personal + Realm bank tracking ported from coa-bagnon (detects CoA `BANK_PERMISSIONS_PAYLOAD`, personal=per-char, realm=per-realm; surfaced in Search + BagUsage tooltip). **New:** Woodcutting + Woodworking columns on the Skills tab (CoA custom professions). NOTE: Skills "all professions" redesign, profession data population, character icons, and reputation factions are still in progress. - **3.3.002b-coa.8** — Title bar reads just `Altoholic ` (from the live `.toc`), dropping the "by Thaoky (Edited by Telkar-RG 1.04a)" string. Window now opens at the AtlasLoot-ish default scale (`UIScale` 1.4, ≈ 1105×640); scale is applied on every open (upstream only applied it after visiting Options), with a one-time bump for profiles still on the old 1.0 default. - **3.3.002b-coa.7** — Skills tab: `GetColor()` now nil-safe and the per-skill rank fields (`skillRank1/2`, `cooking`, `firstaid`, `fishing`, `riding`) default to `0` — they're nil for chars `DataStore_Characters` hasn't scanned, which crashed the Skills summary (`floor(rank/…)` arithmetic and the `>= 300` riding check). - **3.3.002b-coa.6** — Final straggler: guarded `AccountSharing.lua` realm/name line (name getter was the last `format` arg, so a no-value collapsed it to a format error). Concludes the frame sweep.