Files
coa-altoholic/Altoholic/Characters.lua
T
florian.berthold 0565051302
release / release (push) Successful in 5s
coa.10: CoA reputation factions (data-driven) + custom-class icons + all-professions Skills
- Reputation view rebuilt data-driven from each char's scanned factions grouped
  by in-game category; CoA custom factions (and future ones) appear automatically.
  Old hardcoded tree kept only as an icon lookup.
- CoA custom-class icons (classes 12-32) render from bundled atlas
  Altoholic/images/coa-classes.blp (texcoords from coa-details) instead of the
  Warrior glue-icon fallback in ShowClassIcons.
- Skills tab shows ALL known professions (dynamic list incl Woodcutting/Woodworking),
  not 2 fixed slots; DataStore_Skills scans on PLAYER_ENTERING_WORLD/SKILL_LINES_CHANGED
  (fixes 'no profession data' that only scanned on ghost-release).
2026-05-29 15:55:25 +02:00

303 lines
8.6 KiB
Lua

local addonName = ...
local addon = _G[addonName]
local WHITE = "|cFFFFFFFF"
local THIS_ACCOUNT = "Default"
local INFO_REALM_LINE = 0
local INFO_CHARACTER_LINE = 1
local INFO_TOTAL_LINE = 2
local THISREALM_THISACCOUNT = 1
local THISREALM_ALLACCOUNTS = 2
local ALLREALMS_THISACCOUNT = 3
local ALLREALMS_ALLACCOUNTS = 4
addon.Characters = {}
local ns = addon.Characters -- ns = namespace
local characterList
local view
local function ProcessRealms(func)
local mode = addon.Options:Get("TabSummaryMode")
local thisRealm = GetRealmName()
-- this account only
if mode == THISREALM_THISACCOUNT then
func(THIS_ACCOUNT, thisRealm)
elseif mode == ALLREALMS_THISACCOUNT then
for realm in pairs(DataStore:GetRealms()) do
func(THIS_ACCOUNT, realm)
end
-- all accounts
elseif mode == THISREALM_ALLACCOUNTS then
for account in pairs(DataStore:GetAccounts()) do
for realm in pairs(DataStore:GetRealms(account)) do
if realm == thisRealm then
func(account, realm)
end
end
end
elseif mode == ALLREALMS_ALLACCOUNTS then
for account in pairs(DataStore:GetAccounts()) do
for realm in pairs(DataStore:GetRealms(account)) do
func(account, realm)
end
end
end
end
local totalMoney
local totalPlayed
local totalLevels
local realmCount
local function AddRealm(AccountName, RealmName)
local comm = Altoholic.Comm.Sharing
if comm.SharingInProgress then
if comm.account == AccountName and RealmName == GetRealmName() then
-- if we're trying to add the account+realm we're currently copying, then don't add it now.
return
end
end
local realmMoney = 0
local realmPlayed = 0
local realmLevels = 0
local realmBagSlots = 0
local realmFreeBagSlots = 0
local realmBankSlots = 0
local realmFreeBankSlots = 0
-- 1) Add the realm name
table.insert(characterList, { linetype = INFO_REALM_LINE + (realmCount*3),
isCollapsed = false,
account = AccountName,
realm = RealmName
} )
-- 2) Add the characters
for characterName, character in pairs(DataStore:GetCharacters(RealmName, AccountName)) do
-- CoA: characters can know ALL professions at once (no retail 2-primary
-- limit) plus the customs Woodcutting/Woodworking. Build a dynamic list of
-- every known primary profession instead of the old fixed 2 slots. Each
-- entry carries its own name/rank/spellID(icon) so Skills.lua can render an
-- arbitrary number of professions. GetPrimaryProfessionList never returns
-- nil (returns {} for unscanned chars), but guard anyway.
local professions = {}
if DataStore.GetPrimaryProfessionList then
local list = DataStore:GetPrimaryProfessionList(character) or {}
for _, p in ipairs(list) do
professions[#professions + 1] = {
name = p.name,
rank = p.rank or 0,
spellID = DataStore:GetProfessionSpellID(p.name),
}
end
end
table.insert(characterList, { linetype = INFO_CHARACTER_LINE + (realmCount*3),
key = character,
professions = professions, -- CoA: dynamic list of all primary professions
cooking = DataStore:GetCookingRank(character),
firstaid = DataStore:GetFirstAidRank(character),
fishing = DataStore:GetFishingRank(character),
riding = DataStore:GetRidingRank(character),
} )
realmLevels = realmLevels + (DataStore:GetCharacterLevel(character) or 0)
realmMoney = realmMoney + (DataStore:GetMoney(character) or 0)
realmPlayed = realmPlayed + (DataStore:GetPlayTime(character) or 0)
realmBagSlots = realmBagSlots + (DataStore:GetNumBagSlots(character) or 0)
realmFreeBagSlots = realmFreeBagSlots + (DataStore:GetNumFreeBagSlots(character) or 0)
realmBankSlots = realmBankSlots + (DataStore:GetNumBankSlots(character) or 0)
realmFreeBankSlots = realmFreeBankSlots + (DataStore:GetNumFreeBankSlots(character) or 0)
end -- end char
-- 3) Add the totals
table.insert(characterList, { linetype = INFO_TOTAL_LINE + (realmCount*3),
level = WHITE .. realmLevels,
money = realmMoney,
played = Altoholic:GetTimeString(realmPlayed),
bagSlots = realmBagSlots,
freeBagSlots = realmFreeBagSlots,
bankSlots = realmBankSlots,
freeBankSlots = realmFreeBankSlots
} )
totalMoney = totalMoney + realmMoney
totalPlayed = totalPlayed + realmPlayed
totalLevels = totalLevels + realmLevels
realmCount = realmCount + 1
end
function ns:BuildList()
characterList = characterList or {}
wipe(characterList)
totalMoney = 0
totalPlayed = 0
totalLevels = 0
realmCount = 0 -- will be required for sorting purposes
ProcessRealms(AddRealm)
AltoholicFrameTotalLv:SetText(format("%s |rLv", WHITE .. totalLevels))
AltoholicFrameTotalGold:SetText(format(GOLD_AMOUNT_TEXTURE, floor( totalMoney / 10000 ), 13, 13))
AltoholicFrameTotalPlayed:SetText(floor(totalPlayed / 86400) .. "|cFFFFD700d")
end
local function AddRealmView(AccountName, RealmName)
for index, line in pairs(characterList) do
if mod(line.linetype, 3) == INFO_REALM_LINE then
if (line.account == AccountName) and (line.realm == RealmName) then
-- insert index to current line (INFO_REALM_LINE)
table.insert(view, index)
index = index + 1
-- insert index to the rest of the realm
local linetype = mod(characterList[index].linetype, 3)
while (linetype ~= INFO_REALM_LINE) do
table.insert(view, index)
index = index + 1
if index > #characterList then
return
end
linetype = mod(characterList[index].linetype, 3)
end
return
end
end
end
end
function ns:BuildView()
-- The character info index is a small table that basically indexes character info
-- ex: character info contains data for 4 realms on two accounts, but the index only cares about the summary tab filter,
-- and indexes just one realm, or one account
view = view or {}
wipe(view)
ProcessRealms(AddRealmView)
end
local function SortByPrimarySkill(a, b, skillName, ascending)
if (a.linetype ~= b.linetype) then -- sort by linetype first ..
return a.linetype < b.linetype
else -- and when they're identical, sort by field xx
if mod(a.linetype, 3) ~= INFO_CHARACTER_LINE then
return false -- don't swap lines if they're not INFO_CHARACTER_LINE
end
local skillA = DataStore:GetSkillInfo(a.key, a[skillName])
local skillB = DataStore:GetSkillInfo(b.key, b[skillName])
if ascending then
return skillA < skillB
else
return skillA > skillB
end
end
end
local function SortByFunction(a, b, func, ascending)
if (a.linetype ~= b.linetype) then -- sort by linetype first ..
return a.linetype < b.linetype
else -- and when they're identical, sort by func xx
if mod(a.linetype, 3) ~= INFO_CHARACTER_LINE then
return false -- don't swap lines if they're not INFO_CHARACTER_LINE
end
local retA = DataStore[func](self, a.key) or 0 -- set to zero if a return value is nil, so that they can be compared
local retB = DataStore[func](self, b.key) or 0
if ascending then
return retA < retB
else
return retA > retB
end
end
end
function ns:Sort(frame, field)
local ascending = frame.ascendingSort
-- Primary Skill
if (field == "skillName1") or (field == "skillName2") then
table.sort(characterList, function(a, b) return SortByPrimarySkill(a, b, field, ascending)
end)
else
table.sort(characterList, function(a, b) return SortByFunction(a, b, field, ascending) end)
end
addon.Tabs.Summary:Refresh()
end
function ns:Get(index)
return characterList[index]
end
function ns:GetView()
return view
end
function ns:GetNum()
return #characterList or 0
end
function ns:GetInfo(index)
-- with the line number in the characterList table, return the name, realm & account of a char.
local lineType = ns:GetLineType(index)
if lineType == INFO_REALM_LINE then
local line = characterList[index]
return _, line.realm, line.account
elseif lineType == INFO_CHARACTER_LINE then
local account, realm, name = strsplit(".", characterList[index].key)
return name, realm, account
end
end
function ns:GetLineType(index)
local c = characterList[index] -- CoA: hover can fire with a stale/out-of-range line id; callers (Level_OnEnter) already handle a nil return
if not c then return end
return mod(c.linetype, 3)
end
function ns:GetField(index, field)
local character = characterList[index]
if character then
return character[field]
end
end
function ns:ToggleView(frame)
for _, line in pairs(characterList) do
if mod(line.linetype, 3) == INFO_REALM_LINE then
line.isCollapsed = (frame.isCollapsed) or false
end
end
end
function ns:ToggleHeader(frame)
local line = frame:GetParent():GetID()
if line == 0 then return end
local header = characterList[line]
if header.isCollapsed ~= nil then
if header.isCollapsed == true then
header.isCollapsed = false
else
header.isCollapsed = true
end
end
end