Compare commits

..

6 Commits

Author SHA1 Message Date
florian.berthold ad54312ad9 coa.8: simplify title bar + default to AtlasLoot-size window
release / release (push) Successful in 6s
- Title bar: 'Altoholic <toc version>' (was 'Altoholic v.. by Thaoky (Edited by
  Telkar-RG 1.04a)'); reads GetAddOnMetadata Version so it tracks releases. Drop
  dead VERSION_STRING.
- Default UIScale 1.0 -> 1.4 (~AtlasLoot 1105x640). Apply scale in OnShow (was only
  applied after visiting Options); one-time migration bumps old-default profiles.
  Options reset/default slider -> 1.4.
2026-05-29 15:29:55 +02:00
florian.berthold 11c47a86db coa.7: guard Skills tab summary against unscanned skill ranks
release / release (push) Successful in 5s
GetColor() did floor(rank/..) with no nil-guard and riding did 'field >= 300';
skillRank1/2/cooking/firstaid/fishing/riding are nil for chars DataStore_Characters
hasn't scanned. GetColor now defaults rank to 0 and each field falls back to 0.
2026-05-29 15:22:21 +02:00
florian.berthold 86e5b3485f coa.6: guard AccountSharing realm/name format (last straggler)
release / release (push) Successful in 5s
2026-05-29 10:44:59 +02:00
florian.berthold 97e38d5c3d coa.5: refactor char display into guarded helpers; fix missed sites; restore login scan
release / release (push) Successful in 5s
- Extract AddCharacterTooltipHeader() + SetCharacterRowNameLevel() (Altoholic.lua);
  nil-guards centralized, callers in AccountSummary/Activity/BagUsage/Skills/tooltip.
- Fix sites the manual sweep missed: Skills.lua (row + skill ranks), Keys.lua x3,
  ShowClassIcons sort (Altoholic.lua:705, getters bypass their own or-0 via the wrapper).
- Restore login scan: OnPlayerAlive was ghost-only (fdcb25a) so iLvl never populated;
  now scans once per session. Removed dated DEBUG leftovers.
2026-05-29 01:02:24 +02:00
florian.berthold 3fde42454e coa.4: rebrand title to Exiles fork + frame hardening changelog
release / release (push) Successful in 4s
Title drops Telkar-RG's personal 1.04a; now 'Altoholic (Exiles)'.
Author keeps Thaoky/Telkar-RG credit. Bundles the frame partial-record
guards from the previous commit.
2026-05-28 23:54:32 +02:00
florian.berthold f19ff36733 Harden Altoholic frames against partial alt records (no-value char getters)
DataStore char-based getters return *no value* for any module that hasn't
scanned a given char (DataStore.lua: 'if not arg1.lastUpdate then return end').
Fresh CoA alts have partial per-module data, so the frames crashed feeding
'no value' into format()/concat/arithmetic/pairs. Guarded every such site:
AccountSummary, Activity, BagUsage, Quests, Reputations, TabCharacters,
DrawCharacterTooltip, recipe tooltip. No DataStore contract change.
2026-05-28 23:45:09 +02:00
17 changed files with 131 additions and 103 deletions
+51 -27
View File
@@ -17,7 +17,6 @@ local TEAL = "|cFF00FF9A"
local GOLD = "|cFFFFD700"
local THIS_ACCOUNT = "Default"
local VERSION_STRING = "1.04a"
Altoholic.ClassInfo = {
["MAGE"] = "|cFF69CCF0",
@@ -249,10 +248,12 @@ end
-- *** Event Handlers ***
local hasScannedThisSession
local function OnPlayerAlive()
-- print("Altoholic.lua") -- DEBUG 2025 07 21
if not UnitIsGhost("player") then return end -- only scan if player released spirit and went to graveyard
-- CoA: scan once at login (see DataStore_Inventory / commit fdcb25a). FRIENDLIST_UPDATE also
-- keeps the friends list fresh; this just guarantees an initial scan without rescanning on res.
if hasScannedThisSession then return end
hasScannedThisSession = true
ScanFriends()
end
@@ -332,7 +333,10 @@ function addon:OnEnable()
addon:RegisterEvent("AUCTION_HOUSE_SHOW", addon.AuctionHouse.OnShow)
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 player = UnitName("player")
@@ -398,7 +402,17 @@ function addon:ToggleUI()
end
function addon:OnShow()
SetPortraitTexture(AltoholicFramePortrait, "player");
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.
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
end
AltoholicFrame:SetScale(O.UIScale or 1.4)
addon.Characters:BuildList()
addon.Characters:BuildView()
@@ -585,6 +599,22 @@ function addon:GetDelayInDays(delay)
return floor((time() - delay) / 86400)
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)
-- timeStamp = value when time() was last called for a given variable (ex: last time the mailbox was checked)
if not timeStamp then
@@ -679,21 +709,18 @@ function Altoholic:ShowClassIcons()
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_sort = {}
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
-- 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)
-- DEBUG_CHARLIST = CharNameList
-- print("-- altoholic DEBUG READY")
-- ####################
-- for characterName, character in pairs(DS:GetCharacters(realm, account)) do
for _,charTbl in ipairs(CharNameList_sort) do
local characterName, character = charTbl[1], charTbl[2]
@@ -763,25 +790,22 @@ function Altoholic:DrawCharacterTooltip(self, charName)
AltoTooltip:SetOwner(self, "ANCHOR_LEFT");
AltoTooltip:ClearLines();
AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character))
AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"],
GREEN..DS:GetCharacterLevel(character), DS:GetCharacterRace(character), DS:GetCharacterClass(character)),1,1,1)
Altoholic:AddCharacterTooltipHeader(character)
local zone, subZone = DS:GetLocation(character)
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..zone, GOLD..subZone),1,1,1)
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..(zone or "?"), GOLD..(subZone or "")),1,1,1)
local restXP = DS:GetRestXP(character)
if restXP and restXP > 0 then
AltoTooltip:AddLine(format("%s: %s", L["Rest XP"], GREEN..restXP),1,1,1)
end
AltoTooltip:AddLine("Average iLevel: " .. GREEN .. format("%.1f", DS:GetAverageItemLevel(character)),1,1,1);
AltoTooltip:AddLine("Average iLevel: " .. GREEN .. format("%.1f", DS:GetAverageItemLevel(character) or 0),1,1,1);
if IsAddOnLoaded("DataStore_Achievements") then
if DS:GetNumCompletedAchievements(character) > 0 then
AltoTooltip:AddLine(ACHIEVEMENTS_COMPLETED ..": " .. GREEN .. DS:GetNumCompletedAchievements(character) .. "/"..DS:GetNumAchievements(character))
AltoTooltip:AddLine(ACHIEVEMENT_TITLE ..": " .. GREEN .. DS:GetNumAchievementPoints(character))
if (DS:GetNumCompletedAchievements(character) or 0) > 0 then
AltoTooltip:AddLine(ACHIEVEMENTS_COMPLETED ..": " .. GREEN .. DS:GetNumCompletedAchievements(character) .. "/"..(DS:GetNumAchievements(character) or 0))
AltoTooltip:AddLine(ACHIEVEMENT_TITLE ..": " .. GREEN .. (DS:GetNumAchievementPoints(character) or 0))
end
end
+2 -2
View File
@@ -1,5 +1,5 @@
## Interface: 30300
## Title: Altoholic (|cFF69CCF0Telkar-RG|cFFFFFFFF 1.04a|r |cFFFFD100CoA|r)
## Title: Altoholic (|cFFFFD100Exiles|r)
## X-Curse-Packaged-Version: r90
## X-Curse-Project-Name: Altoholic
@@ -13,7 +13,7 @@
## Author: Thaoky, Telkar-RG
## X-Edited-By: Exiles (Sub-Net) — florian.berthold@sub-net.at
## Version: 3.3.002b-coa.3
## Version: 3.3.002b-coa.8
## 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
+1 -1
View File
@@ -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.0,
UIScale = 1.4, -- CoA: open at ~AtlasLoot footprint (832x447 * 1.4 = 1165x626 vs AtlasLoot 1105x640)
UITransparency = 1.0,
ClampWindowToScreen = 0,
+1 -1
View File
@@ -279,7 +279,7 @@ local ContentScrollFrame_Desc = {
[CHARACTER_HEADER_LINE] = {
GetText = function(self, line)
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,
GetOffset = function(self, line)
return 20
+15 -18
View File
@@ -249,12 +249,11 @@ function ns:Update()
_G[entry..i.."Name"]:SetWidth(170)
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
_G[entry..i.."NameNormalText"]:SetWidth(170)
_G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character), DS:GetCharacterClass(character)))
_G[entry..i.."Level"]:SetText(GREEN .. DS:GetCharacterLevel(character))
addon:SetCharacterRowNameLevel(entry, i, icon, character)
_G[entry..i.."Money"]:SetText(addon:GetMoneyString(DS:GetMoney(character)))
_G[entry..i.."Played"]:SetText(addon:GetTimeString(DS:GetPlayTime(character)))
_G[entry..i.."XP"]:SetText(GREEN .. DS:GetXPRate(character) .. "%")
_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.."XP"]:SetText(GREEN .. (DS:GetXPRate(character) or 0) .. "%")
if DS:GetCharacterLevel(character) == MAX_PLAYER_LEVEL then
_G[entry..i.."Rested"]:SetText(WHITE .. "0%")
@@ -262,7 +261,7 @@ function ns:Update()
_G[entry..i.."Rested"]:SetText( addon:GetRestedXP(character) )
end
_G[entry..i.."AvgILevelNormalText"]:SetText(YELLOW..format("%.1f", DS:GetAverageItemLevel(character)))
_G[entry..i.."AvgILevelNormalText"]:SetText(YELLOW..format("%.1f", DS:GetAverageItemLevel(character) or 0))
elseif (lineType == INFO_TOTAL_LINE) then
_G[entry..i.."Collapse"]:Hide()
@@ -342,23 +341,21 @@ function ns:Level_OnEnter(frame)
AltoTooltip:ClearLines();
AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT");
AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character))
AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"],
GREEN..DS:GetCharacterLevel(character), DS:GetCharacterRace(character), DS:GetCharacterClass(character)),1,1,1)
addon:AddCharacterTooltipHeader(character)
local zone, subZone = DS:GetLocation(character)
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..zone, GOLD..subZone),1,1,1)
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..(zone or "?"), GOLD..(subZone or "")),1,1,1)
local guildName = DS:GetGuildInfo(character)
if guildName then
AltoTooltip:AddLine(format("%s: %s", GUILD, GREEN..guildName),1,1,1)
end
AltoTooltip:AddLine(EXPERIENCE_COLON .. " "
.. GREEN .. DS:GetXP(character) .. WHITE .. "/"
.. GREEN .. DS:GetXPMax(character) .. WHITE .. " ("
.. GREEN .. DS:GetXPRate(character) .. "%"
.. WHITE .. ")",1,1,1);
AltoTooltip:AddLine(EXPERIENCE_COLON .. " "
.. GREEN .. (DS:GetXP(character) or 0) .. WHITE .. "/"
.. GREEN .. (DS:GetXPMax(character) or 0) .. WHITE .. " ("
.. GREEN .. (DS:GetXPRate(character) or 0) .. "%"
.. WHITE .. ")",1,1,1);
local restXP = DS:GetRestXP(character)
if restXP and restXP > 0 then
@@ -448,7 +445,7 @@ function ns:AIL_OnEnter(frame)
AltoTooltip:ClearLines();
AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT");
AltoTooltip:AddLine(DS:GetColoredCharacterName(character),1,1,1);
AltoTooltip:AddLine(WHITE .. L["Average Item Level"] ..": " .. GREEN.. format("%.1f", DS:GetAverageItemLevel(character)),1,1,1);
AltoTooltip:AddLine(WHITE .. L["Average Item Level"] ..": " .. GREEN.. format("%.1f", DS:GetAverageItemLevel(character) or 0),1,1,1);
addon:AiLTooltip()
AltoTooltip:Show();
+10 -13
View File
@@ -100,8 +100,7 @@ function ns:Update()
_G[entry..i.."Name"]:SetWidth(170)
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
_G[entry..i.."NameNormalText"]:SetWidth(170)
_G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character), DS:GetCharacterClass(character)))
_G[entry..i.."Level"]:SetText(GREEN .. DS:GetCharacterLevel(character))
addon:SetCharacterRowNameLevel(entry, i, icon, character)
local color
local num = DS:GetNumMails(character) or 0
@@ -112,7 +111,7 @@ function ns:Update()
color = GREEN -- green by default, red if at least one mail is about to expire
local threshold = DataStore:GetOption("DataStore_Mails", "MailWarningThreshold")
if DS:GetNumExpiredMails(character, threshold) > 0 then
if (DS:GetNumExpiredMails(character, threshold) or 0) > 0 then
color = RED
end
end
@@ -181,18 +180,16 @@ function ns:OnEnter(self)
AltoTooltip:ClearLines();
AltoTooltip:SetOwner(self, "ANCHOR_RIGHT");
AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character))
AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"],
GREEN..DS:GetCharacterLevel(character), DS:GetCharacterRace(character), DS:GetCharacterClass(character)),1,1,1)
addon:AddCharacterTooltipHeader(character)
local zone, subZone = DS:GetLocation(character)
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..zone, GOLD..subZone),1,1,1)
AltoTooltip:AddLine(EXPERIENCE_COLON .. " "
.. GREEN .. DS:GetXP(character) .. WHITE .. "/"
.. GREEN .. DS:GetXPMax(character) .. WHITE .. " ("
.. GREEN .. DS:GetXPRate(character) .. "%"
.. WHITE .. ")",1,1,1);
AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..(zone or "?"), GOLD..(subZone or "")),1,1,1)
AltoTooltip:AddLine(EXPERIENCE_COLON .. " "
.. GREEN .. (DS:GetXP(character) or 0) .. WHITE .. "/"
.. GREEN .. (DS:GetXPMax(character) or 0) .. WHITE .. " ("
.. GREEN .. (DS:GetXPRate(character) or 0) .. "%"
.. WHITE .. ")",1,1,1);
local restXP = DS:GetRestXP(character)
if restXP and restXP > 0 then
+14 -17
View File
@@ -96,26 +96,25 @@ function ns:Update()
_G[entry..i.."Name"]:SetWidth(170)
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
_G[entry..i.."NameNormalText"]:SetWidth(170)
_G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character), DS:GetCharacterClass(character)))
_G[entry..i.."Level"]:SetText(GREEN .. DS:GetCharacterLevel(character))
_G[entry..i.."FreeBags"]:SetText(GREEN .. DS:GetNumFreeBagSlots(character))
_G[entry..i.."FreeBank"]:SetText(GREEN .. DS:GetNumFreeBankSlots(character))
addon:SetCharacterRowNameLevel(entry, i, icon, character)
_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.."BagSlotsNormalText"]:SetJustifyH("LEFT")
_G[entry..i.."BankSlotsNormalText"]:SetJustifyH("LEFT")
-- Normal bags
_G[entry..i.."BagSlotsNormalText"]:SetText(format("%s/%s|r/%s|r/%s|r/%s |r(%s|r)",
DS:GetContainerSize(character, 0),
WHITE .. DS:GetContainerSize(character, 1),
WHITE .. DS:GetContainerSize(character, 2),
WHITE .. DS:GetContainerSize(character, 3),
WHITE .. DS:GetContainerSize(character, 4),
CYAN .. DS:GetNumBagSlots(character)))
DS:GetContainerSize(character, 0) or 0,
WHITE .. (DS:GetContainerSize(character, 1) or 0),
WHITE .. (DS:GetContainerSize(character, 2) or 0),
WHITE .. (DS:GetContainerSize(character, 3) or 0),
WHITE .. (DS:GetContainerSize(character, 4) or 0),
CYAN .. (DS:GetNumBagSlots(character) or 0)))
-- Bank bags
if DS:GetNumBankSlots(character) < 28 then
if (DS:GetNumBankSlots(character) or 0) < 28 then
_G[entry..i.."BankSlotsNormalText"]:SetText(L["Bank not visited yet"])
else
_G[entry..i.."BankSlotsNormalText"]:SetText(format("%s/%s|r/%s|r/%s|r/%s|r/%s|r/%s|r/%s |r(%s|r)",
@@ -182,9 +181,7 @@ function ns:OnEnter(self)
AltoTooltip:ClearLines();
AltoTooltip:SetOwner(self, "ANCHOR_RIGHT");
AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character))
AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"],
GREEN..DS:GetCharacterLevel(character), DS:GetCharacterRace(character), DS:GetCharacterClass(character)),1,1,1)
addon:AddCharacterTooltipHeader(character)
AltoTooltip:AddLine(" ",1,1,1);
local id = self:GetID()
@@ -203,7 +200,7 @@ function ns:OnEnter(self)
end
numSlots = DS:GetNumBagSlots(character)
numFree = DS:GetNumFreeBagSlots(character)
elseif DS:GetNumBankSlots(character) < 28 then
elseif (DS:GetNumBankSlots(character) or 0) < 28 then
AltoTooltip:AddLine(L["Bank not visited yet"],1,1,1);
AltoTooltip:Show();
return
+3 -3
View File
@@ -789,7 +789,7 @@ function ns:Item_OnEnter(frame)
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT")
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(" ")
local questDone, cr,cg,cb
@@ -848,7 +848,7 @@ function ns:Item_OnEnter(frame)
else
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT")
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(" ")
local questDone, cr,cg,cb
@@ -912,7 +912,7 @@ function ns:Item_OnEnter(frame)
else
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT")
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(L["Required reputation"] .. ":",1,1,1)
+1 -1
View File
@@ -40,7 +40,7 @@ function ns:Update()
local DS = DataStore
if DS:GetQuestLogSize(character) == 0 then
if (DS:GetQuestLogSize(character) or 0) == 0 then
AltoholicTabCharactersStatus:SetText(L["No quest found for "] .. addon:GetCurrentCharacter())
addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 18)
return
+1 -1
View File
@@ -310,7 +310,7 @@ function ns:OnEnter(frame)
AltoTooltip:SetOwner(frame, "ANCHOR_LEFT");
AltoTooltip:ClearLines();
AltoTooltip:AddLine(DS:GetColoredCharacterName(character) .. WHITE .. " @ " .. TEAL .. faction,1,1,1);
AltoTooltip:AddLine((DS:GetColoredCharacterName(character) or "?") .. WHITE .. " @ " .. TEAL .. faction,1,1,1);
rate = format("%d", floor(rate)) .. "%"
AltoTooltip:AddLine(format("%s: %d/%d (%s)", status, currentLevel, maxLevel, rate),1,1,1 )
+10 -8
View File
@@ -109,8 +109,7 @@ function ns:Update()
_G[entry..i.."Name"]:SetWidth(170)
_G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0)
_G[entry..i.."NameNormalText"]:SetWidth(170)
_G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character), DS:GetCharacterClass(character)))
_G[entry..i.."Level"]:SetText(GREEN .. DS:GetCharacterLevel(character))
addon:SetCharacterRowNameLevel(entry, i, icon, character)
-- profession 1
local field = Characters:GetField(line, "spellID1")
@@ -120,7 +119,7 @@ function ns:Update()
else
icon = ""
end
field = Characters:GetField(line, "skillRank1")
field = Characters:GetField(line, "skillRank1") or 0
_G[entry..i.."Skill1NormalText"]:SetText(icon .. ns:GetColor(field) .. field)
-- profession 2
@@ -131,29 +130,29 @@ function ns:Update()
else
icon = ""
end
field = Characters:GetField(line, "skillRank2")
field = Characters:GetField(line, "skillRank2") or 0
_G[entry..i.."Skill2NormalText"]:SetText(icon .. ns:GetColor(field) .. field)
-- cooking
-- icon = addon:TextureToFontstring(addon:GetSpellIcon(2550), size, size) .. " "
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)
-- first aid
-- icon = addon:TextureToFontstring(addon:GetSpellIcon(3273), size, size) .. " "
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)
-- fishing
-- icon = addon:TextureToFontstring(addon:GetSpellIcon(7733), size, size) .. " "
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)
-- riding
field = Characters:GetField(line, "riding")
field = Characters:GetField(line, "riding") or 0
if field >= 300 then
-- 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)
@@ -251,6 +250,7 @@ function ns:OnEnter(frame)
local DS = DataStore
local character = DS:GetCharacter(Characters:GetInfo(line))
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
@@ -268,6 +268,7 @@ function ns:OnEnter(frame)
skillName = L["Rogue Proficiencies"]
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
suggestion = addon:GetSuggestion(L["Lockpicking"], curLock)
end
@@ -399,6 +400,7 @@ end
local skillColors = { RECIPE_GREY, RED, ORANGE, YELLOW, GREEN }
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
return skillColors[ floor(rank / (skillCap/4)) + 1 ]
end
+1 -1
View File
@@ -228,7 +228,7 @@ function ns:UpdateViewIcons()
AltoholicTabCharacters_FirstAid:Show()
local i = 1
for skillName, skill in pairs(DS:GetPrimaryProfessions(character)) do
for skillName, skill in pairs(DS:GetPrimaryProfessions(character) or {}) do -- CoA: getter returns no value for chars DataStore_Crafts hasn't scanned
local itemName = "AltoholicTabCharacters_Prof" .. i
local item = _G[itemName]
local spellID = DataStore:GetProfessionSpellID(skillName)
+5 -5
View File
@@ -161,7 +161,7 @@
</Scripts>
</Slider>
<Slider name="$parent_SliderScale" inherits="OptionsSliderTemplate" minValue="0.5" maxValue="4.0" defaultValue="1.0" valueStep="0.1">
<Slider name="$parent_SliderScale" inherits="OptionsSliderTemplate" minValue="0.5" maxValue="4.0" defaultValue="1.4" valueStep="0.1">
<Size>
<AbsDimension x="180" y="16"/>
</Size>
@@ -199,10 +199,10 @@
<Scripts>
<OnClick>
local name = self:GetParent():GetName()
_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)
_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)
</OnClick>
</Scripts>
</Button>
+1 -1
View File
@@ -448,7 +448,7 @@ local function GetRecipeOwners(professionName, link, recipeLevel)
table.insert(know, coloredName)
else
local currentLevel = DataStore:GetSkillInfo(character, professionName)
if currentLevel > 0 then
if currentLevel and currentLevel > 0 then -- CoA: getter returns no value for chars DataStore_Skills hasn't scanned
if currentLevel < recipeLevel then
table.insert(willLearn, format("%s |r(%d)", coloredName, currentLevel))
else
+6 -3
View File
@@ -167,10 +167,13 @@ function ScanInventory()
end
-- *** Event Handlers ***
local hasScannedThisSession
local function OnPlayerAlive()
-- print("DataStore_Inventory.lua") -- DEBUG 2025 07 21
if not UnitIsGhost("player") then return end -- only scan if player released spirit and went to graveyard
-- CoA: scan once at login. PLAYER_ALIVE also fires on resurrect / Feign-Death cancel where gear
-- 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()
end
+1 -1
View File
@@ -3,7 +3,7 @@
## Notes: Stores information about character inventory
## Author: Thaoky (EU-Marécages de Zangar)
## X-Edited-By: Exiles (Sub-Net)
## Version: 3.3.002-coa.2
## Version: 3.3.002-coa.5
## Dependencies: DataStore
## OptionalDeps: Ace3
## SavedVariables: DataStore_InventoryDB
+8
View File
@@ -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`.
- **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.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).
- `GetRestXPRate` — guard nil/zero `XPMax` and nil `lastLogoutTimestamp` (`nil ~= 0` was true and crashed).