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.