Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec868716ed | |||
| ad54312ad9 | |||
| 11c47a86db | |||
| 86e5b3485f | |||
| 97e38d5c3d |
+42
-20
@@ -17,7 +17,6 @@ local TEAL = "|cFF00FF9A"
|
|||||||
local GOLD = "|cFFFFD700"
|
local GOLD = "|cFFFFD700"
|
||||||
|
|
||||||
local THIS_ACCOUNT = "Default"
|
local THIS_ACCOUNT = "Default"
|
||||||
local VERSION_STRING = "1.04a"
|
|
||||||
|
|
||||||
Altoholic.ClassInfo = {
|
Altoholic.ClassInfo = {
|
||||||
["MAGE"] = "|cFF69CCF0",
|
["MAGE"] = "|cFF69CCF0",
|
||||||
@@ -249,10 +248,12 @@ end
|
|||||||
|
|
||||||
|
|
||||||
-- *** Event Handlers ***
|
-- *** Event Handlers ***
|
||||||
|
local hasScannedThisSession
|
||||||
local function OnPlayerAlive()
|
local function OnPlayerAlive()
|
||||||
-- print("Altoholic.lua") -- DEBUG 2025 07 21
|
-- CoA: scan once at login (see DataStore_Inventory / commit fdcb25a). FRIENDLIST_UPDATE also
|
||||||
if not UnitIsGhost("player") then return end -- only scan if player released spirit and went to graveyard
|
-- keeps the friends list fresh; this just guarantees an initial scan without rescanning on res.
|
||||||
|
if hasScannedThisSession then return end
|
||||||
|
hasScannedThisSession = true
|
||||||
ScanFriends()
|
ScanFriends()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -332,7 +333,10 @@ function addon:OnEnable()
|
|||||||
addon:RegisterEvent("AUCTION_HOUSE_SHOW", addon.AuctionHouse.OnShow)
|
addon:RegisterEvent("AUCTION_HOUSE_SHOW", addon.AuctionHouse.OnShow)
|
||||||
addon:RegisterEvent("PLAYER_TALENT_UPDATE", addon.Talents.OnUpdate);
|
addon:RegisterEvent("PLAYER_TALENT_UPDATE", addon.Talents.OnUpdate);
|
||||||
|
|
||||||
AltoholicFrameName:SetText("Altoholic |cFFFFFFFF".. addon.Version .. "|r by |cFF69CCF0Thaoky|r" .. " (Edited by |cFF69CCF0Telkar-RG|r ".."|cFFFFFFFF".. VERSION_STRING .."|r)")
|
-- CoA: just "Altoholic <version>" in the title bar (Exiles branding + author credit live in the .toc).
|
||||||
|
-- Read the live .toc Version so it tracks each -coa.N release without editing this string.
|
||||||
|
local titleVersion = GetAddOnMetadata(addonName, "Version") or addon.Version
|
||||||
|
AltoholicFrameName:SetText("Altoholic |cFFFFFFFF".. titleVersion .."|r")
|
||||||
|
|
||||||
local realm = GetRealmName()
|
local realm = GetRealmName()
|
||||||
local player = UnitName("player")
|
local player = UnitName("player")
|
||||||
@@ -398,7 +402,15 @@ function addon:ToggleUI()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function addon:OnShow()
|
function addon:OnShow()
|
||||||
SetPortraitTexture(AltoholicFramePortrait, "player");
|
SetPortraitTexture(AltoholicFramePortrait, "player");
|
||||||
|
|
||||||
|
-- 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 O and O.UIScale then
|
||||||
|
AltoholicFrame:SetScale(O.UIScale)
|
||||||
|
end
|
||||||
|
|
||||||
addon.Characters:BuildList()
|
addon.Characters:BuildList()
|
||||||
addon.Characters:BuildView()
|
addon.Characters:BuildView()
|
||||||
@@ -585,6 +597,22 @@ function addon:GetDelayInDays(delay)
|
|||||||
return floor((time() - delay) / 86400)
|
return floor((time() - delay) / 86400)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- CoA: shared, nil-safe character display helpers.
|
||||||
|
-- DataStore char-based getters return *no value* for any module that hasn't
|
||||||
|
-- scanned a given character (DataStore.lua: "if not arg1.lastUpdate then return end").
|
||||||
|
-- Fresh alts have partial per-module data, so every field is guarded here once
|
||||||
|
-- instead of being copy-pasted (and missed) across the frames.
|
||||||
|
function Altoholic:AddCharacterTooltipHeader(character)
|
||||||
|
AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character) or "?", DS:GetColoredCharacterFaction(character) or "")
|
||||||
|
AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"],
|
||||||
|
GREEN..(DS:GetCharacterLevel(character) or 0), DS:GetCharacterRace(character) or "", DS:GetCharacterClass(character) or ""), 1, 1, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Altoholic:SetCharacterRowNameLevel(entry, i, icon, character)
|
||||||
|
_G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character) or "?", DS:GetCharacterClass(character) or ""))
|
||||||
|
_G[entry..i.."Level"]:SetText(GREEN .. (DS:GetCharacterLevel(character) or 0))
|
||||||
|
end
|
||||||
|
|
||||||
function Altoholic:FormatDelay(timeStamp)
|
function Altoholic:FormatDelay(timeStamp)
|
||||||
-- timeStamp = value when time() was last called for a given variable (ex: last time the mailbox was checked)
|
-- timeStamp = value when time() was last called for a given variable (ex: last time the mailbox was checked)
|
||||||
if not timeStamp then
|
if not timeStamp then
|
||||||
@@ -679,21 +707,18 @@ function Altoholic:ShowClassIcons()
|
|||||||
local realm, account = Altoholic:GetCurrentRealm()
|
local realm, account = Altoholic:GetCurrentRealm()
|
||||||
|
|
||||||
|
|
||||||
-- ####################
|
-- Sort characters by level first, then average item level. The getters yield no value
|
||||||
|
-- for alts whose Characters/Inventory module hasn't scanned them, so default [3]/[4] to 0.
|
||||||
local CharNameList = DS:GetCharacters(realm, account)
|
local CharNameList = DS:GetCharacters(realm, account)
|
||||||
local CharNameList_sort = {}
|
local CharNameList_sort = {}
|
||||||
|
|
||||||
for k,v in pairs(CharNameList) do
|
for k,v in pairs(CharNameList) do
|
||||||
table.insert(CharNameList_sort,{k,v, DS:GetAverageItemLevel(v), DS:GetCharacterLevel(v)})
|
table.insert(CharNameList_sort, {k, v, DS:GetAverageItemLevel(v) or 0, DS:GetCharacterLevel(v) or 0})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- sort for level first, avg iLevel secondly
|
|
||||||
table.sort(CharNameList_sort, function(a,b) return b[3]+b[4]*10000 < a[3]+a[4]*10000 end)
|
table.sort(CharNameList_sort, function(a,b) return b[3]+b[4]*10000 < a[3]+a[4]*10000 end)
|
||||||
-- DEBUG_CHARLIST = CharNameList
|
|
||||||
-- print("-- altoholic DEBUG READY")
|
|
||||||
-- ####################
|
|
||||||
|
|
||||||
|
|
||||||
-- for characterName, character in pairs(DS:GetCharacters(realm, account)) do
|
-- for characterName, character in pairs(DS:GetCharacters(realm, account)) do
|
||||||
for _,charTbl in ipairs(CharNameList_sort) do
|
for _,charTbl in ipairs(CharNameList_sort) do
|
||||||
local characterName, character = charTbl[1], charTbl[2]
|
local characterName, character = charTbl[1], charTbl[2]
|
||||||
@@ -763,10 +788,7 @@ function Altoholic:DrawCharacterTooltip(self, charName)
|
|||||||
|
|
||||||
AltoTooltip:SetOwner(self, "ANCHOR_LEFT");
|
AltoTooltip:SetOwner(self, "ANCHOR_LEFT");
|
||||||
AltoTooltip:ClearLines();
|
AltoTooltip:ClearLines();
|
||||||
AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character))
|
Altoholic:AddCharacterTooltipHeader(character)
|
||||||
|
|
||||||
AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"],
|
|
||||||
GREEN..(DS:GetCharacterLevel(character) or 0), DS:GetCharacterRace(character) or "", DS:GetCharacterClass(character) or ""),1,1,1)
|
|
||||||
|
|
||||||
local zone, subZone = DS:GetLocation(character)
|
local zone, subZone = DS:GetLocation(character)
|
||||||
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..(zone or "?"), GOLD..(subZone or "")),1,1,1)
|
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..(zone or "?"), GOLD..(subZone or "")),1,1,1)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
## Author: Thaoky, Telkar-RG
|
## Author: Thaoky, Telkar-RG
|
||||||
## X-Edited-By: Exiles (Sub-Net) — florian.berthold@sub-net.at
|
## X-Edited-By: Exiles (Sub-Net) — florian.berthold@sub-net.at
|
||||||
## Version: 3.3.002b-coa.4
|
## Version: 3.3.002b-coa.9
|
||||||
## X-Category: Inventory, Tradeskill, Mail
|
## X-Category: Inventory, Tradeskill, Mail
|
||||||
## X-Localizations: enUS, frFR, zhCN, zhTW, deDE, koKR, esES, esMX, ruRU
|
## X-Localizations: enUS, frFR, zhCN, zhTW, deDE, koKR, esES, esMX, ruRU
|
||||||
## X-Website: http://wow.curse.com/downloads/wow-addons/details/altoholic.aspx
|
## X-Website: http://wow.curse.com/downloads/wow-addons/details/altoholic.aspx
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ local ContentScrollFrame_Desc = {
|
|||||||
[CHARACTER_HEADER_LINE] = {
|
[CHARACTER_HEADER_LINE] = {
|
||||||
GetText = function(self, line)
|
GetText = function(self, line)
|
||||||
local _, realm, name = strsplit(".", line.key)
|
local _, realm, name = strsplit(".", line.key)
|
||||||
return format("%s|r / %s", WHITE..realm, DataStore:GetColoredCharacterName(line.key))
|
return format("%s|r / %s", WHITE..realm, DataStore:GetColoredCharacterName(line.key) or "?")
|
||||||
end,
|
end,
|
||||||
GetOffset = function(self, line)
|
GetOffset = function(self, line)
|
||||||
return 20
|
return 20
|
||||||
|
|||||||
@@ -249,10 +249,7 @@ function ns:Update()
|
|||||||
_G[entry..i.."Name"]:SetWidth(170)
|
_G[entry..i.."Name"]:SetWidth(170)
|
||||||
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
|
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
|
||||||
_G[entry..i.."NameNormalText"]:SetWidth(170)
|
_G[entry..i.."NameNormalText"]:SetWidth(170)
|
||||||
-- CoA: DataStore char-based getters return *no value* for any module that hasn't scanned this char
|
addon:SetCharacterRowNameLevel(entry, i, icon, character)
|
||||||
-- (DataStore.lua: "if not arg1.lastUpdate then return end"). Fresh alts have partial module data, so guard every result.
|
|
||||||
_G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character) or "?", DS:GetCharacterClass(character) or ""))
|
|
||||||
_G[entry..i.."Level"]:SetText(GREEN .. (DS:GetCharacterLevel(character) or 0))
|
|
||||||
|
|
||||||
_G[entry..i.."Money"]:SetText(addon:GetMoneyString(DS:GetMoney(character) or 0))
|
_G[entry..i.."Money"]:SetText(addon:GetMoneyString(DS:GetMoney(character) or 0))
|
||||||
_G[entry..i.."Played"]:SetText(addon:GetTimeString(DS:GetPlayTime(character) or 0))
|
_G[entry..i.."Played"]:SetText(addon:GetTimeString(DS:GetPlayTime(character) or 0))
|
||||||
@@ -344,9 +341,7 @@ function ns:Level_OnEnter(frame)
|
|||||||
AltoTooltip:ClearLines();
|
AltoTooltip:ClearLines();
|
||||||
AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT");
|
AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT");
|
||||||
|
|
||||||
AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character))
|
addon:AddCharacterTooltipHeader(character)
|
||||||
AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"],
|
|
||||||
GREEN..(DS:GetCharacterLevel(character) or 0), DS:GetCharacterRace(character) or "", DS:GetCharacterClass(character) or ""),1,1,1)
|
|
||||||
|
|
||||||
local zone, subZone = DS:GetLocation(character)
|
local zone, subZone = DS:GetLocation(character)
|
||||||
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..(zone or "?"), GOLD..(subZone or "")),1,1,1)
|
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..(zone or "?"), GOLD..(subZone or "")),1,1,1)
|
||||||
|
|||||||
@@ -100,8 +100,7 @@ function ns:Update()
|
|||||||
_G[entry..i.."Name"]:SetWidth(170)
|
_G[entry..i.."Name"]:SetWidth(170)
|
||||||
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
|
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
|
||||||
_G[entry..i.."NameNormalText"]:SetWidth(170)
|
_G[entry..i.."NameNormalText"]:SetWidth(170)
|
||||||
_G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character) or "?", DS:GetCharacterClass(character) or ""))
|
addon:SetCharacterRowNameLevel(entry, i, icon, character)
|
||||||
_G[entry..i.."Level"]:SetText(GREEN .. (DS:GetCharacterLevel(character) or 0))
|
|
||||||
|
|
||||||
local color
|
local color
|
||||||
local num = DS:GetNumMails(character) or 0
|
local num = DS:GetNumMails(character) or 0
|
||||||
@@ -181,9 +180,7 @@ function ns:OnEnter(self)
|
|||||||
AltoTooltip:ClearLines();
|
AltoTooltip:ClearLines();
|
||||||
AltoTooltip:SetOwner(self, "ANCHOR_RIGHT");
|
AltoTooltip:SetOwner(self, "ANCHOR_RIGHT");
|
||||||
|
|
||||||
AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character))
|
addon:AddCharacterTooltipHeader(character)
|
||||||
AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"],
|
|
||||||
GREEN..(DS:GetCharacterLevel(character) or 0), DS:GetCharacterRace(character) or "", DS:GetCharacterClass(character) or ""),1,1,1)
|
|
||||||
|
|
||||||
local zone, subZone = DS:GetLocation(character)
|
local zone, subZone = DS:GetLocation(character)
|
||||||
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..(zone or "?"), GOLD..(subZone or "")),1,1,1)
|
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..(zone or "?"), GOLD..(subZone or "")),1,1,1)
|
||||||
|
|||||||
@@ -96,8 +96,7 @@ function ns:Update()
|
|||||||
_G[entry..i.."Name"]:SetWidth(170)
|
_G[entry..i.."Name"]:SetWidth(170)
|
||||||
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
|
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
|
||||||
_G[entry..i.."NameNormalText"]:SetWidth(170)
|
_G[entry..i.."NameNormalText"]:SetWidth(170)
|
||||||
_G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character) or "?", DS:GetCharacterClass(character) or ""))
|
addon:SetCharacterRowNameLevel(entry, i, icon, character)
|
||||||
_G[entry..i.."Level"]:SetText(GREEN .. (DS:GetCharacterLevel(character) or 0))
|
|
||||||
|
|
||||||
_G[entry..i.."FreeBags"]:SetText(GREEN .. (DS:GetNumFreeBagSlots(character) or 0))
|
_G[entry..i.."FreeBags"]:SetText(GREEN .. (DS:GetNumFreeBagSlots(character) or 0))
|
||||||
_G[entry..i.."FreeBank"]:SetText(GREEN .. (DS:GetNumFreeBankSlots(character) or 0))
|
_G[entry..i.."FreeBank"]:SetText(GREEN .. (DS:GetNumFreeBankSlots(character) or 0))
|
||||||
@@ -182,9 +181,7 @@ function ns:OnEnter(self)
|
|||||||
|
|
||||||
AltoTooltip:ClearLines();
|
AltoTooltip:ClearLines();
|
||||||
AltoTooltip:SetOwner(self, "ANCHOR_RIGHT");
|
AltoTooltip:SetOwner(self, "ANCHOR_RIGHT");
|
||||||
AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character))
|
addon:AddCharacterTooltipHeader(character)
|
||||||
AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"],
|
|
||||||
GREEN..(DS:GetCharacterLevel(character) or 0), DS:GetCharacterRace(character) or "", DS:GetCharacterClass(character) or ""),1,1,1)
|
|
||||||
AltoTooltip:AddLine(" ",1,1,1);
|
AltoTooltip:AddLine(" ",1,1,1);
|
||||||
|
|
||||||
local id = self:GetID()
|
local id = self:GetID()
|
||||||
@@ -221,5 +218,15 @@ function ns:OnEnter(self)
|
|||||||
|
|
||||||
AltoTooltip:AddLine(" ",1,1,1);
|
AltoTooltip:AddLine(" ",1,1,1);
|
||||||
AltoTooltip:AddLine(CYAN .. numSlots .. " |r" .. L["slots"] .. " (" .. GREEN .. numFree .. "|r " ..L["free"] .. ") ",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
|
end
|
||||||
|
|||||||
@@ -460,7 +460,9 @@ function ns:Level_OnClick(self, button)
|
|||||||
if button ~= "LeftButton" then return end
|
if button ~= "LeftButton" then return end
|
||||||
|
|
||||||
local id = self:GetParent():GetID()
|
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]
|
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
|
if line.lineType == NORMALPLAYER_LINE then return end
|
||||||
|
|
||||||
local member = self:GetParent().CharName
|
local member = self:GetParent().CharName
|
||||||
|
|||||||
@@ -789,7 +789,7 @@ function ns:Item_OnEnter(frame)
|
|||||||
|
|
||||||
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT")
|
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT")
|
||||||
AltoTooltip:ClearLines()
|
AltoTooltip:ClearLines()
|
||||||
AltoTooltip:AddLine( format("%s|r: %s", DS:GetColoredCharacterName(character), nameKey) )
|
AltoTooltip:AddLine( format("%s|r: %s", DS:GetColoredCharacterName(character) or "?", nameKey) )
|
||||||
AltoTooltip:AddLine(" ")
|
AltoTooltip:AddLine(" ")
|
||||||
|
|
||||||
local questDone, cr,cg,cb
|
local questDone, cr,cg,cb
|
||||||
@@ -848,7 +848,7 @@ function ns:Item_OnEnter(frame)
|
|||||||
else
|
else
|
||||||
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT")
|
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT")
|
||||||
AltoTooltip:ClearLines()
|
AltoTooltip:ClearLines()
|
||||||
AltoTooltip:AddLine( format("%s|r: %s", DS:GetColoredCharacterName(character), nameKey) )
|
AltoTooltip:AddLine( format("%s|r: %s", DS:GetColoredCharacterName(character) or "?", nameKey) )
|
||||||
AltoTooltip:AddLine(" ")
|
AltoTooltip:AddLine(" ")
|
||||||
|
|
||||||
local questDone, cr,cg,cb
|
local questDone, cr,cg,cb
|
||||||
@@ -912,7 +912,7 @@ function ns:Item_OnEnter(frame)
|
|||||||
else
|
else
|
||||||
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT")
|
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT")
|
||||||
AltoTooltip:ClearLines()
|
AltoTooltip:ClearLines()
|
||||||
AltoTooltip:AddLine( format("%s|r: %s", DS:GetColoredCharacterName(character), nameKey) )
|
AltoTooltip:AddLine( format("%s|r: %s", DS:GetColoredCharacterName(character) or "?", nameKey) )
|
||||||
AltoTooltip:AddLine(" ")
|
AltoTooltip:AddLine(" ")
|
||||||
AltoTooltip:AddLine(L["Required reputation"] .. ":",1,1,1)
|
AltoTooltip:AddLine(L["Required reputation"] .. ":",1,1,1)
|
||||||
|
|
||||||
|
|||||||
@@ -603,15 +603,17 @@ local function BrowseCharacter(character)
|
|||||||
currentResultLocation = L["Bank"]
|
currentResultLocation = L["Bank"]
|
||||||
elseif (containerName == "Bag-2") then
|
elseif (containerName == "Bag-2") then
|
||||||
currentResultLocation = KEYRING
|
currentResultLocation = KEYRING
|
||||||
|
elseif string.sub(containerName, 1, 5) == "PBank" then -- CoA personal bank tab
|
||||||
|
currentResultLocation = "Personal Bank"
|
||||||
else
|
else
|
||||||
local bagNum = tonumber(string.sub(containerName, 4))
|
local bagNum = tonumber(string.sub(containerName, 4))
|
||||||
if (bagNum >= 0) and (bagNum <= 4) then
|
if (bagNum >= 0) and (bagNum <= 4) then
|
||||||
currentResultLocation = L["Bags"]
|
currentResultLocation = L["Bags"]
|
||||||
else
|
else
|
||||||
currentResultLocation = L["Bank"]
|
currentResultLocation = L["Bank"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for slotID = 1, container.size do
|
for slotID = 1, container.size do
|
||||||
itemID, itemLink, itemCount = DS:GetSlotInfo(container, slotID)
|
itemID, itemLink, itemCount = DS:GetSlotInfo(container, slotID)
|
||||||
|
|
||||||
@@ -710,7 +712,39 @@ local function BrowseRealm(realm, account, bothFactions)
|
|||||||
currentResultType = nil
|
currentResultType = nil
|
||||||
currentResultLocation = nil
|
currentResultLocation = nil
|
||||||
end
|
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 ?
|
if addon.Options:Get("IncludeGuildSkills") == 1 and string.len(currentValue) > 1 then -- Check guild professions ?
|
||||||
local guild = addon:GetGuild()
|
local guild = addon:GetGuild()
|
||||||
if guild and LTL then -- LTL won't be valid if there's a version mismatch (see :Init() )
|
if guild and LTL then -- LTL won't be valid if there's a version mismatch (see :Init() )
|
||||||
|
|||||||
+43
-12
@@ -86,7 +86,9 @@ function ns:Update()
|
|||||||
_G[entry..i.."FirstAidNormalText"]:SetText("")
|
_G[entry..i.."FirstAidNormalText"]:SetText("")
|
||||||
_G[entry..i.."FishingNormalText"]:SetText("")
|
_G[entry..i.."FishingNormalText"]:SetText("")
|
||||||
_G[entry..i.."RidingNormalText"]:SetText("")
|
_G[entry..i.."RidingNormalText"]:SetText("")
|
||||||
|
_G[entry..i.."WoodcuttingNormalText"]:SetText("")
|
||||||
|
_G[entry..i.."WoodworkingNormalText"]:SetText("")
|
||||||
|
|
||||||
_G[ entry..i ]:SetID(line)
|
_G[ entry..i ]:SetID(line)
|
||||||
_G[ entry..i ]:Show()
|
_G[ entry..i ]:Show()
|
||||||
i = i + 1
|
i = i + 1
|
||||||
@@ -109,8 +111,7 @@ function ns:Update()
|
|||||||
_G[entry..i.."Name"]:SetWidth(170)
|
_G[entry..i.."Name"]:SetWidth(170)
|
||||||
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
|
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
|
||||||
_G[entry..i.."NameNormalText"]:SetWidth(170)
|
_G[entry..i.."NameNormalText"]:SetWidth(170)
|
||||||
_G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character), DS:GetCharacterClass(character)))
|
addon:SetCharacterRowNameLevel(entry, i, icon, character)
|
||||||
_G[entry..i.."Level"]:SetText(GREEN .. DS:GetCharacterLevel(character))
|
|
||||||
|
|
||||||
-- profession 1
|
-- profession 1
|
||||||
local field = Characters:GetField(line, "spellID1")
|
local field = Characters:GetField(line, "spellID1")
|
||||||
@@ -120,7 +121,7 @@ function ns:Update()
|
|||||||
else
|
else
|
||||||
icon = ""
|
icon = ""
|
||||||
end
|
end
|
||||||
field = Characters:GetField(line, "skillRank1")
|
field = Characters:GetField(line, "skillRank1") or 0
|
||||||
_G[entry..i.."Skill1NormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
_G[entry..i.."Skill1NormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
||||||
|
|
||||||
-- profession 2
|
-- profession 2
|
||||||
@@ -131,29 +132,29 @@ function ns:Update()
|
|||||||
else
|
else
|
||||||
icon = ""
|
icon = ""
|
||||||
end
|
end
|
||||||
field = Characters:GetField(line, "skillRank2")
|
field = Characters:GetField(line, "skillRank2") or 0
|
||||||
_G[entry..i.."Skill2NormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
_G[entry..i.."Skill2NormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
||||||
|
|
||||||
-- cooking
|
-- cooking
|
||||||
-- icon = addon:TextureToFontstring(addon:GetSpellIcon(2550), size, size) .. " "
|
-- icon = addon:TextureToFontstring(addon:GetSpellIcon(2550), size, size) .. " "
|
||||||
icon = addon:TextureToFontstring2(addon:GetSpellIcon(2550), size, size, inset, inset, inset, inset) .. " "
|
icon = addon:TextureToFontstring2(addon:GetSpellIcon(2550), size, size, inset, inset, inset, inset) .. " "
|
||||||
field = Characters:GetField(line, "cooking")
|
field = Characters:GetField(line, "cooking") or 0
|
||||||
_G[entry..i.."CookingNormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
_G[entry..i.."CookingNormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
||||||
|
|
||||||
-- first aid
|
-- first aid
|
||||||
-- icon = addon:TextureToFontstring(addon:GetSpellIcon(3273), size, size) .. " "
|
-- icon = addon:TextureToFontstring(addon:GetSpellIcon(3273), size, size) .. " "
|
||||||
icon = addon:TextureToFontstring2(addon:GetSpellIcon(3273), size, size, inset, inset, inset, inset) .. " "
|
icon = addon:TextureToFontstring2(addon:GetSpellIcon(3273), size, size, inset, inset, inset, inset) .. " "
|
||||||
field = Characters:GetField(line, "firstaid")
|
field = Characters:GetField(line, "firstaid") or 0
|
||||||
_G[entry..i.."FirstAidNormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
_G[entry..i.."FirstAidNormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
||||||
|
|
||||||
-- fishing
|
-- fishing
|
||||||
-- icon = addon:TextureToFontstring(addon:GetSpellIcon(7733), size, size) .. " "
|
-- icon = addon:TextureToFontstring(addon:GetSpellIcon(7733), size, size) .. " "
|
||||||
icon = addon:TextureToFontstring2(addon:GetSpellIcon(7733), size, size, inset, inset, inset, inset) .. " "
|
icon = addon:TextureToFontstring2(addon:GetSpellIcon(7733), size, size, inset, inset, inset, inset) .. " "
|
||||||
field = Characters:GetField(line, "fishing")
|
field = Characters:GetField(line, "fishing") or 0
|
||||||
_G[entry..i.."FishingNormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
_G[entry..i.."FishingNormalText"]:SetText(icon .. ns:GetColor(field) .. field)
|
||||||
|
|
||||||
-- riding
|
-- riding
|
||||||
field = Characters:GetField(line, "riding")
|
field = Characters:GetField(line, "riding") or 0
|
||||||
if field >= 300 then
|
if field >= 300 then
|
||||||
-- icon = addon:TextureToFontstring("Interface\\Icons\\Ability_Mount_Gryphon_01", size, size) .. " "
|
-- icon = addon:TextureToFontstring("Interface\\Icons\\Ability_Mount_Gryphon_01", size, size) .. " "
|
||||||
icon = addon:TextureToFontstring2("Interface\\Icons\\ability_mount_drake_bronze", size, size, inset, inset, inset, inset)
|
icon = addon:TextureToFontstring2("Interface\\Icons\\ability_mount_drake_bronze", size, size, inset, inset, inset, inset)
|
||||||
@@ -192,6 +193,20 @@ function ns:Update()
|
|||||||
end
|
end
|
||||||
|
|
||||||
_G[entry..i.."RidingNormalText"]:SetText(icon .. ns:GetColor(field, 300) .. field)
|
_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
|
elseif (lineType == INFO_TOTAL_LINE) then
|
||||||
_G[entry..i.."Collapse"]:Hide()
|
_G[entry..i.."Collapse"]:Hide()
|
||||||
_G[entry..i.."Name"]:SetWidth(200)
|
_G[entry..i.."Name"]:SetWidth(200)
|
||||||
@@ -205,6 +220,8 @@ function ns:Update()
|
|||||||
_G[entry..i.."FirstAidNormalText"]:SetText("")
|
_G[entry..i.."FirstAidNormalText"]:SetText("")
|
||||||
_G[entry..i.."FishingNormalText"]:SetText("")
|
_G[entry..i.."FishingNormalText"]:SetText("")
|
||||||
_G[entry..i.."RidingNormalText"]:SetText("")
|
_G[entry..i.."RidingNormalText"]:SetText("")
|
||||||
|
_G[entry..i.."WoodcuttingNormalText"]:SetText("")
|
||||||
|
_G[entry..i.."WoodworkingNormalText"]:SetText("")
|
||||||
end
|
end
|
||||||
_G[ entry..i ]:SetID(line)
|
_G[ entry..i ]:SetID(line)
|
||||||
_G[ entry..i ]:Show()
|
_G[ entry..i ]:Show()
|
||||||
@@ -246,14 +263,22 @@ function ns:OnEnter(frame)
|
|||||||
skillName = GetSpellInfo(24303) -- Fishing
|
skillName = GetSpellInfo(24303) -- Fishing
|
||||||
elseif id == 6 then
|
elseif id == 6 then
|
||||||
skillName = L["Riding"]
|
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
|
end
|
||||||
|
|
||||||
local DS = DataStore
|
local DS = DataStore
|
||||||
local character = DS:GetCharacter(Characters:GetInfo(line))
|
local character = DS:GetCharacter(Characters:GetInfo(line))
|
||||||
local curRank, maxRank = DS:GetSkillInfo(character, skillName)
|
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)
|
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
|
if id == 6 then -- riding
|
||||||
rank = ns:GetColor(curRank, 300) .. curRank .. "/" .. maxRank
|
rank = ns:GetColor(curRank, 300) .. curRank .. "/" .. maxRank
|
||||||
else
|
else
|
||||||
@@ -268,6 +293,7 @@ function ns:OnEnter(frame)
|
|||||||
skillName = L["Rogue Proficiencies"]
|
skillName = L["Rogue Proficiencies"]
|
||||||
|
|
||||||
local curLock, maxLock = DS:GetSkillInfo(character, L["Lockpicking"])
|
local curLock, maxLock = DS:GetSkillInfo(character, L["Lockpicking"])
|
||||||
|
curLock, maxLock = curLock or 0, maxLock or 0 -- CoA: guard unscanned lockpicking
|
||||||
rank = TEAL .. L["Lockpicking"] .. " " .. curLock .. "/" .. maxLock
|
rank = TEAL .. L["Lockpicking"] .. " " .. curLock .. "/" .. maxLock
|
||||||
suggestion = addon:GetSuggestion(L["Lockpicking"], curLock)
|
suggestion = addon:GetSuggestion(L["Lockpicking"], curLock)
|
||||||
end
|
end
|
||||||
@@ -277,7 +303,7 @@ function ns:OnEnter(frame)
|
|||||||
AltoTooltip:AddLine(skillName,1,1,1);
|
AltoTooltip:AddLine(skillName,1,1,1);
|
||||||
AltoTooltip:AddLine(GREEN..rank,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
|
if skillName ~= GetSpellInfo(13614) and skillName ~= GetSpellInfo(8613) then -- no display for herbalism & skinning
|
||||||
AltoTooltip:AddLine(" ");
|
AltoTooltip:AddLine(" ");
|
||||||
|
|
||||||
@@ -362,6 +388,10 @@ function ns:OnClick(frame, button)
|
|||||||
skillName = GetSpellInfo(2550) -- cooking
|
skillName = GetSpellInfo(2550) -- cooking
|
||||||
elseif id == 4 then
|
elseif id == 4 then
|
||||||
skillName = GetSpellInfo(3273) -- First Aid
|
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
|
end
|
||||||
|
|
||||||
local DS = DataStore
|
local DS = DataStore
|
||||||
@@ -399,6 +429,7 @@ end
|
|||||||
local skillColors = { RECIPE_GREY, RED, ORANGE, YELLOW, GREEN }
|
local skillColors = { RECIPE_GREY, RED, ORANGE, YELLOW, GREEN }
|
||||||
|
|
||||||
function ns:GetColor(rank, skillCap)
|
function ns:GetColor(rank, skillCap)
|
||||||
|
rank = rank or 0 -- CoA: skill fields are nil for chars DataStore_Characters hasn't scanned
|
||||||
skillCap = skillCap or 450
|
skillCap = skillCap or 450
|
||||||
return skillColors[ floor(rank / (skillCap/4)) + 1 ]
|
return skillColors[ floor(rank / (skillCap/4)) + 1 ]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
<Button name="AltoSkillsTemplate" virtual="true">
|
<Button name="AltoSkillsTemplate" virtual="true">
|
||||||
<Size>
|
<Size>
|
||||||
<AbsDimension x="615" y="22"/>
|
<AbsDimension x="745" y="22"/>
|
||||||
</Size>
|
</Size>
|
||||||
<Layers>
|
<Layers>
|
||||||
<Layer level="BACKGROUND">
|
<Layer level="BACKGROUND">
|
||||||
@@ -162,12 +162,30 @@
|
|||||||
</Anchor>
|
</Anchor>
|
||||||
</Anchors>
|
</Anchors>
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button name="$parentWoodcutting" inherits="AltoSkillButtonTemplate" id="8">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="BOTTOMLEFT" relativeTo="$parentRiding" relativePoint="BOTTOMRIGHT">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="0" y="0"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
</Button>
|
||||||
|
<Button name="$parentWoodworking" inherits="AltoSkillButtonTemplate" id="9">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="BOTTOMLEFT" relativeTo="$parentWoodcutting" relativePoint="BOTTOMRIGHT">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="0" y="0"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
</Button>
|
||||||
</Frames>
|
</Frames>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Frame name="AltoholicFrameSkills" parent="AltoholicTabSummary" hidden="true">
|
<Frame name="AltoholicFrameSkills" parent="AltoholicTabSummary" hidden="true">
|
||||||
<Size>
|
<Size>
|
||||||
<AbsDimension x="615" y="306"/>
|
<AbsDimension x="745" y="306"/>
|
||||||
</Size>
|
</Size>
|
||||||
<Anchors>
|
<Anchors>
|
||||||
<Anchor point="TOPRIGHT">
|
<Anchor point="TOPRIGHT">
|
||||||
|
|||||||
@@ -432,13 +432,13 @@ function Altoholic:MoveMinimapIcon()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Altoholic.Options:Get(name)
|
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]
|
return addon.db.global.options[name]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Altoholic.Options:Set(name, value)
|
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
|
addon.db.global.options[name] = value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -35,6 +35,24 @@ local MSG_BANKTAB_TRANSFER = 6 -- .. or send the data
|
|||||||
|
|
||||||
local AddonDB_Defaults = {
|
local AddonDB_Defaults = {
|
||||||
global = {
|
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 = {
|
Guilds = {
|
||||||
['*'] = { -- ["Account.Realm.Name"]
|
['*'] = { -- ["Account.Realm.Name"]
|
||||||
money = nil,
|
money = nil,
|
||||||
@@ -204,6 +222,16 @@ end
|
|||||||
local BAGS = 1 -- All bags, 0 to 11, and keyring ( id -2 )
|
local BAGS = 1 -- All bags, 0 to 11, and keyring ( id -2 )
|
||||||
local BANK = 2 -- 28 main slots
|
local BANK = 2 -- 28 main slots
|
||||||
local GUILDBANK = 3 -- 98 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 = {
|
local ContainerTypes = {
|
||||||
[BAGS] = {
|
[BAGS] = {
|
||||||
@@ -262,9 +290,81 @@ local ContainerTypes = {
|
|||||||
GetCooldown = function(self, slotID)
|
GetCooldown = function(self, slotID)
|
||||||
return nil
|
return nil
|
||||||
end,
|
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 ***
|
-- *** Scanning functions ***
|
||||||
local function ScanContainer(bagID, containerType)
|
local function ScanContainer(bagID, containerType)
|
||||||
local Container = ContainerTypes[containerType]
|
local Container = ContainerTypes[containerType]
|
||||||
@@ -273,8 +373,15 @@ local function ScanContainer(bagID, containerType)
|
|||||||
if containerType == GUILDBANK then
|
if containerType == GUILDBANK then
|
||||||
local thisGuild = GetThisGuild()
|
local thisGuild = GetThisGuild()
|
||||||
if not thisGuild then return end
|
if not thisGuild then return end
|
||||||
|
|
||||||
bag = thisGuild.Tabs[bagID] -- bag is actually the current tab
|
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
|
else
|
||||||
bag = addon.ThisCharacter.Containers["Bag" .. bagID]
|
bag = addon.ThisCharacter.Containers["Bag" .. bagID]
|
||||||
wipe(bag.cooldowns) -- does not exist for a guild bank
|
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
|
bag.cooldowns[index] = startTime .."|".. duration .. "|" .. 1
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
local function ScanBagSlotsInfo()
|
local function ScanBagSlotsInfo()
|
||||||
@@ -463,25 +576,76 @@ local function OnBankFrameOpened()
|
|||||||
addon:RegisterEvent("PLAYERBANKSLOTS_CHANGED", OnPlayerBankSlotsChanged)
|
addon:RegisterEvent("PLAYERBANKSLOTS_CHANGED", OnPlayerBankSlotsChanged)
|
||||||
end
|
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()
|
local function OnGuildBankFrameClosed()
|
||||||
addon:UnregisterEvent("GUILDBANKFRAME_CLOSED")
|
addon:UnregisterEvent("GUILDBANKFRAME_CLOSED")
|
||||||
addon:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED")
|
addon:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED")
|
||||||
|
|
||||||
local guildName = GetGuildInfo("player")
|
-- only broadcast guild bank timestamps for the actual guild bank
|
||||||
if guildName then
|
if addon.coaBankType == "guild" then
|
||||||
GuildBroadcast(MSG_SEND_BANK_TIMESTAMPS, GetBankTimestamps(guildName))
|
local guildName = GetGuildInfo("player")
|
||||||
|
if guildName then
|
||||||
|
GuildBroadcast(MSG_SEND_BANK_TIMESTAMPS, GetBankTimestamps(guildName))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
addon.coaBankType = nil
|
||||||
|
addon.coaBankAvailableTabs = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function OnGuildBankBagSlotsChanged()
|
local function OnGuildBankBagSlotsChanged()
|
||||||
ScanContainer(GetCurrentGuildBankTab(), GUILDBANK)
|
local currentTab = GetCurrentGuildBankTab()
|
||||||
ScanGuildBankInfo()
|
|
||||||
|
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
|
end
|
||||||
|
|
||||||
local function OnGuildBankFrameOpened()
|
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("GUILDBANKFRAME_CLOSED", OnGuildBankFrameClosed)
|
||||||
addon:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED", OnGuildBankBagSlotsChanged)
|
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()
|
local thisGuild = GetThisGuild()
|
||||||
if thisGuild then
|
if thisGuild then
|
||||||
thisGuild.money = GetGuildBankMoney()
|
thisGuild.money = GetGuildBankMoney()
|
||||||
@@ -550,19 +714,22 @@ end
|
|||||||
local function _GetContainerItemCount(character, searchedID)
|
local function _GetContainerItemCount(character, searchedID)
|
||||||
local bagCount = 0
|
local bagCount = 0
|
||||||
local bankCount = 0
|
local bankCount = 0
|
||||||
|
local personalBankCount = 0
|
||||||
local id
|
local id
|
||||||
|
|
||||||
for containerName, container in pairs(character.Containers) do
|
for containerName, container in pairs(character.Containers) do
|
||||||
for slotID=1, container.size do
|
for slotID=1, container.size do
|
||||||
id = container.ids[slotID]
|
id = container.ids[slotID]
|
||||||
|
|
||||||
if (id) and (id == searchedID) then
|
if (id) and (id == searchedID) then
|
||||||
local itemCount = container.counts[slotID] or 1
|
local itemCount = container.counts[slotID] or 1
|
||||||
|
|
||||||
if (containerName == "Bag100") then
|
if (containerName == "Bag100") then
|
||||||
bankCount = bankCount + itemCount
|
bankCount = bankCount + itemCount
|
||||||
elseif (containerName == "Bag-2") then
|
elseif (containerName == "Bag-2") then
|
||||||
bagCount = bagCount + itemCount
|
bagCount = bagCount + itemCount
|
||||||
|
elseif string.sub(containerName, 1, #PERSONALBANK_PREFIX) == PERSONALBANK_PREFIX then
|
||||||
|
personalBankCount = personalBankCount + itemCount -- CoA personal bank tab
|
||||||
else
|
else
|
||||||
local bagNum = tonumber(string.sub(containerName, 4))
|
local bagNum = tonumber(string.sub(containerName, 4))
|
||||||
if (bagNum >= 0) and (bagNum <= 4) then
|
if (bagNum >= 0) and (bagNum <= 4) then
|
||||||
@@ -575,7 +742,79 @@ local function _GetContainerItemCount(character, searchedID)
|
|||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
local function _GetNumBagSlots(character)
|
local function _GetNumBagSlots(character)
|
||||||
@@ -721,6 +960,14 @@ local PublicMethods = {
|
|||||||
RejectBankTabRequest = _RejectBankTabRequest,
|
RejectBankTabRequest = _RejectBankTabRequest,
|
||||||
SendBankTabToGuildMember = _SendBankTabToGuildMember,
|
SendBankTabToGuildMember = _SendBankTabToGuildMember,
|
||||||
GetGuildBankTabSuppliers = _GetGuildBankTabSuppliers,
|
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 ***
|
-- *** Guild Comm ***
|
||||||
@@ -809,7 +1056,11 @@ function addon:OnInitialize()
|
|||||||
DataStore:SetCharacterBasedMethod("GetNumFreeBagSlots")
|
DataStore:SetCharacterBasedMethod("GetNumFreeBagSlots")
|
||||||
DataStore:SetCharacterBasedMethod("GetNumBankSlots")
|
DataStore:SetCharacterBasedMethod("GetNumBankSlots")
|
||||||
DataStore:SetCharacterBasedMethod("GetNumFreeBankSlots")
|
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("GetGuildBankItemCount")
|
||||||
DataStore:SetGuildBasedMethod("GetGuildBankTab")
|
DataStore:SetGuildBasedMethod("GetGuildBankTab")
|
||||||
DataStore:SetGuildBasedMethod("GetGuildBankTabName")
|
DataStore:SetGuildBasedMethod("GetGuildBankTabName")
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
## Title: DataStore_Containers
|
## Title: DataStore_Containers
|
||||||
## Notes: Stores information about character bags, bank, and guild banks
|
## Notes: Stores information about character bags, bank, and guild banks
|
||||||
## Author: Thaoky (EU-Marécages de Zangar)
|
## Author: Thaoky (EU-Marécages de Zangar)
|
||||||
## Version: 3.3.001
|
## Version: 3.3.001-coa.9
|
||||||
## Dependencies: DataStore
|
## Dependencies: DataStore
|
||||||
## OptionalDeps: Ace3
|
## OptionalDeps: Ace3
|
||||||
## SavedVariables: DataStore_ContainersDB
|
## SavedVariables: DataStore_ContainersDB
|
||||||
|
|||||||
@@ -167,10 +167,13 @@ function ScanInventory()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- *** Event Handlers ***
|
-- *** Event Handlers ***
|
||||||
|
local hasScannedThisSession
|
||||||
local function OnPlayerAlive()
|
local function OnPlayerAlive()
|
||||||
-- print("DataStore_Inventory.lua") -- DEBUG 2025 07 21
|
-- CoA: scan once at login. PLAYER_ALIVE also fires on resurrect / Feign-Death cancel where gear
|
||||||
if not UnitIsGhost("player") then return end -- only scan if player released spirit and went to graveyard
|
-- is unchanged, so skip those. (The previous "only when ghost" gate also skipped login, so iLvl
|
||||||
|
-- never populated and UNIT_INVENTORY_CHANGED was the only scan path - see commit fdcb25a.)
|
||||||
|
if hasScannedThisSession then return end
|
||||||
|
hasScannedThisSession = true
|
||||||
ScanInventory()
|
ScanInventory()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
## Notes: Stores information about character inventory
|
## Notes: Stores information about character inventory
|
||||||
## Author: Thaoky (EU-Marécages de Zangar)
|
## Author: Thaoky (EU-Marécages de Zangar)
|
||||||
## X-Edited-By: Exiles (Sub-Net)
|
## X-Edited-By: Exiles (Sub-Net)
|
||||||
## Version: 3.3.002-coa.2
|
## Version: 3.3.002-coa.5
|
||||||
## Dependencies: DataStore
|
## Dependencies: DataStore
|
||||||
## OptionalDeps: Ace3
|
## OptionalDeps: Ace3
|
||||||
## SavedVariables: DataStore_InventoryDB
|
## SavedVariables: DataStore_InventoryDB
|
||||||
|
|||||||
@@ -77,6 +77,22 @@ local function _GetRidingRank(character)
|
|||||||
return _GetSkillInfoByCategory(character, L["Secondary Skills"], L["Riding"])
|
return _GetSkillInfoByCategory(character, L["Secondary Skills"], L["Riding"])
|
||||||
end
|
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 = {
|
local PublicMethods = {
|
||||||
GetPrimaryProfessions = _GetPrimaryProfessions,
|
GetPrimaryProfessions = _GetPrimaryProfessions,
|
||||||
GetSecondaryProfessions = _GetSecondaryProfessions,
|
GetSecondaryProfessions = _GetSecondaryProfessions,
|
||||||
@@ -86,6 +102,8 @@ local PublicMethods = {
|
|||||||
GetCookingRank = _GetCookingRank,
|
GetCookingRank = _GetCookingRank,
|
||||||
GetFishingRank = _GetFishingRank,
|
GetFishingRank = _GetFishingRank,
|
||||||
GetRidingRank = _GetRidingRank,
|
GetRidingRank = _GetRidingRank,
|
||||||
|
GetWoodcuttingRank = _GetWoodcuttingRank,
|
||||||
|
GetWoodworkingRank = _GetWoodworkingRank,
|
||||||
}
|
}
|
||||||
|
|
||||||
function addon:OnInitialize()
|
function addon:OnInitialize()
|
||||||
@@ -100,6 +118,8 @@ function addon:OnInitialize()
|
|||||||
DataStore:SetCharacterBasedMethod("GetCookingRank")
|
DataStore:SetCharacterBasedMethod("GetCookingRank")
|
||||||
DataStore:SetCharacterBasedMethod("GetFishingRank")
|
DataStore:SetCharacterBasedMethod("GetFishingRank")
|
||||||
DataStore:SetCharacterBasedMethod("GetRidingRank")
|
DataStore:SetCharacterBasedMethod("GetRidingRank")
|
||||||
|
DataStore:SetCharacterBasedMethod("GetWoodcuttingRank")
|
||||||
|
DataStore:SetCharacterBasedMethod("GetWoodworkingRank")
|
||||||
end
|
end
|
||||||
|
|
||||||
function addon:OnEnable()
|
function addon:OnEnable()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
## Title: DataStore_Skills
|
## Title: DataStore_Skills
|
||||||
## Notes: Stores information about character skills
|
## Notes: Stores information about character skills
|
||||||
## Author: Thaoky (EU-Marécages de Zangar)
|
## Author: Thaoky (EU-Marécages de Zangar)
|
||||||
## Version: 3.3.002
|
## Version: 3.3.002-coa.9
|
||||||
## Dependencies: DataStore
|
## Dependencies: DataStore
|
||||||
## OptionalDeps: Ace3
|
## OptionalDeps: Ace3
|
||||||
## SavedVariables: DataStore_SkillsDB
|
## SavedVariables: DataStore_SkillsDB
|
||||||
|
|||||||
@@ -5,6 +5,14 @@ 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`.
|
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 <version>` (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.
|
||||||
|
- **3.3.002b-coa.5** — Refactor + completeness pass:
|
||||||
|
- Extracted the duplicated character header/row blocks into `Altoholic:AddCharacterTooltipHeader()` and `Altoholic:SetCharacterRowNameLevel()` — the nil-guards now live in one place instead of being copy-pasted across frames.
|
||||||
|
- Fixed crash sites the per-frame sweep had missed: `Skills.lua` (row + skill-rank tooltip), `Keys.lua` (×3 `format` with possibly-nil name), and the latent `ShowClassIcons` sort (`Altoholic.lua` — getters bypass their own `or 0` via the DataStore wrapper).
|
||||||
|
- Restored login scanning: `OnPlayerAlive` in `Altoholic.lua` + `DataStore_Inventory` was gated to ghost-only (commit fdcb25a), so inventory/iLvl never populated on login. Now scans once per session (still skips resurrect/Feign-Death rescans). Removed dated DEBUG leftovers.
|
||||||
- **3.3.002b-coa.4** — Rebranded to the Exiles fork (title `Altoholic (Exiles)`; Thaoky/Telkar-RG still credited as Author). Hardened **all** Altoholic frames against partial alt records: DataStore char-based getters return *no value* for any module that hasn't scanned a char, and the frames assumed full data everywhere. Guarded every `format`/concat/arithmetic/`pairs` site across AccountSummary, Activity, BagUsage, Quests, Reputations, TabCharacters, `DrawCharacterTooltip`, and the recipe tooltip. No DataStore contract change.
|
- **3.3.002b-coa.4** — Rebranded to the Exiles fork (title `Altoholic (Exiles)`; Thaoky/Telkar-RG still credited as Author). Hardened **all** Altoholic frames against partial alt records: DataStore char-based getters return *no value* for any module that hasn't scanned a char, and the frames assumed full data everywhere. Guarded every `format`/concat/arithmetic/`pairs` site across AccountSummary, Activity, BagUsage, Quests, Reputations, TabCharacters, `DrawCharacterTooltip`, and the recipe tooltip. No DataStore contract change.
|
||||||
- **3.3.002b-coa.3** — More partial-record guards in `DataStore_Characters` (own alts seen via guild comm but never fully scanned):
|
- **3.3.002b-coa.3** — More partial-record guards in `DataStore_Characters` (own alts seen via guild comm but never fully scanned):
|
||||||
- `GetXPRate` — guard nil/zero `XPMax` (crashed AccountSummary; also fixes div-by-zero at max level).
|
- `GetXPRate` — guard nil/zero `XPMax` (crashed AccountSummary; also fixes div-by-zero at max level).
|
||||||
|
|||||||
Reference in New Issue
Block a user