mirror of
https://github.com/Lacustat/Freewood-OctoWoW-Pet.git
synced 2026-11-05 03:17:03 +00:00
Freewood-OctoWoW-Pet 0.1.136
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016onJCSHLwhs9udhC9ZLzk9
This commit is contained in:
@@ -0,0 +1,662 @@
|
||||
-- Freewood-OctoWoW-Pet: Tab "Begleiter" im Freewood-Fenster
|
||||
-- Links die Liste der erfassten Begleiter, rechts Kennzahlen, Nahrung und Faehigkeiten.
|
||||
-- Aufbau angelehnt an das Stitch-Design "Jaeger Begleiter" (Filter/Liste links, Details rechts).
|
||||
|
||||
local ADDON, NS = ...
|
||||
|
||||
local FW = _G.Freewood
|
||||
local Pet = NS.Pet
|
||||
if not FW or not Pet then
|
||||
return
|
||||
end
|
||||
|
||||
local UI = FW.UI
|
||||
|
||||
local LIST_W = 252
|
||||
local ROW_H, ROW_GAP = 54, 6
|
||||
local CARD_W, CARD_H, CARD_GAP = 176, 48, 10
|
||||
local ABILITY_H = 30
|
||||
|
||||
local function FormatTime(t)
|
||||
if type(t) ~= "number" or t <= 0 then
|
||||
return "-"
|
||||
end
|
||||
return date("%d.%m.%Y %H:%M", t)
|
||||
end
|
||||
|
||||
local function SortedKeys()
|
||||
local keys = {}
|
||||
for key in pairs(Pet.db.pets) do
|
||||
keys[#keys + 1] = key
|
||||
end
|
||||
table.sort(keys, function(a, b)
|
||||
if a == b then
|
||||
return false
|
||||
end
|
||||
if a == Pet.activeKey then
|
||||
return true
|
||||
end
|
||||
if b == Pet.activeKey then
|
||||
return false
|
||||
end
|
||||
local ra, rb = Pet.db.pets[a], Pet.db.pets[b]
|
||||
local ia, ib = ra.src == "import", rb.src == "import"
|
||||
if ia ~= ib then
|
||||
return not ia
|
||||
end
|
||||
local ua, ub = ra.updated or 0, rb.updated or 0
|
||||
if ua ~= ub then
|
||||
return ua > ub
|
||||
end
|
||||
return a < b
|
||||
end)
|
||||
return keys
|
||||
end
|
||||
|
||||
local function Subtitle(rec)
|
||||
return string.format("%s - %s", rec.family or "?", string.format(FW.L.PET_LEVEL, rec.level or 0))
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Zeile der Liste
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local function CreateListRow(parent, onSelect)
|
||||
local row = CreateFrame("Button", nil, parent)
|
||||
row:SetHeight(ROW_H)
|
||||
|
||||
row.bg = row:CreateTexture(nil, "BACKGROUND")
|
||||
row.bg:SetAllPoints()
|
||||
UI.AddBorder(row, "bronze", 0.6)
|
||||
|
||||
row.icon = row:CreateTexture(nil, "ARTWORK")
|
||||
row.icon:SetSize(34, 34)
|
||||
row.icon:SetPoint("LEFT", row, "LEFT", 8, 0)
|
||||
row.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
||||
|
||||
row.name = UI.CreateLabel(row, "", { font = "heading", size = 13, color = "goldLight" })
|
||||
row.name:SetPoint("TOPLEFT", row, "TOPLEFT", 52, -10)
|
||||
row.name:SetWidth(LIST_W - 130)
|
||||
row.name:SetWordWrap(false)
|
||||
|
||||
row.sub = UI.CreateLabel(row, "", { size = 11, color = "textDim" })
|
||||
row.sub:SetPoint("TOPLEFT", row.name, "BOTTOMLEFT", 0, -6)
|
||||
row.sub:SetWidth(LIST_W - 70)
|
||||
row.sub:SetWordWrap(false)
|
||||
|
||||
row.chip = UI.CreateChip(row, "", "success")
|
||||
row.chip:SetPoint("TOPRIGHT", row, "TOPRIGHT", -10, -9)
|
||||
|
||||
local function Refresh()
|
||||
if row.selected then
|
||||
row.bg:SetColorTexture(UI.Color("hover"))
|
||||
UI.SetBorderColor(row, "gold")
|
||||
elseif row.hover then
|
||||
row.bg:SetColorTexture(UI.Color("hover", 0.7))
|
||||
UI.SetBorderColor(row, "bronze")
|
||||
else
|
||||
row.bg:SetColorTexture(UI.Color("card"))
|
||||
UI.SetBorderColor(row, "bronze", 0.6)
|
||||
end
|
||||
end
|
||||
|
||||
function row:SetSelected(selected)
|
||||
self.selected = selected
|
||||
Refresh()
|
||||
end
|
||||
|
||||
row:SetScript("OnEnter", function()
|
||||
row.hover = true
|
||||
Refresh()
|
||||
end)
|
||||
row:SetScript("OnLeave", function()
|
||||
row.hover = false
|
||||
Refresh()
|
||||
end)
|
||||
row:SetScript("OnClick", function()
|
||||
onSelect(row.key)
|
||||
end)
|
||||
|
||||
Refresh()
|
||||
return row
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Tab
|
||||
------------------------------------------------------------------------
|
||||
|
||||
local function Build(content)
|
||||
local L = FW.L
|
||||
local f = CreateFrame("Frame", nil, content)
|
||||
|
||||
local rows, abilityRows, foodChips = {}, {}, {}
|
||||
|
||||
---------------- linke Spalte ----------------
|
||||
local listTitle = UI.CreateLabel(f, L.PET_LIST_HEADER, { font = "heading", size = 14, color = "goldLight" })
|
||||
listTitle:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
|
||||
|
||||
local listDivider = UI.CreateDivider(f)
|
||||
listDivider:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -26)
|
||||
listDivider:SetWidth(LIST_W)
|
||||
|
||||
local listScroll = UI.CreateScrollFrame(f)
|
||||
listScroll:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -36)
|
||||
listScroll:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 0)
|
||||
listScroll:SetWidth(LIST_W)
|
||||
|
||||
local separator = f:CreateTexture(nil, "ARTWORK")
|
||||
separator:SetColorTexture(UI.Color("bronze", 0.4))
|
||||
separator:SetWidth(1)
|
||||
separator:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 10, 0)
|
||||
separator:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", LIST_W + 10, 0)
|
||||
|
||||
---------------- rechte Spalte ----------------
|
||||
local detail = CreateFrame("Frame", nil, f)
|
||||
detail:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22, 0)
|
||||
detail:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
|
||||
|
||||
local empty = UI.CreateLabel(f, L.PET_EMPTY, { size = 12, color = "textDim", justifyV = "TOP", justify = "LEFT" })
|
||||
empty:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22, -4)
|
||||
empty:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -4)
|
||||
empty:SetWordWrap(true)
|
||||
|
||||
local headIcon = CreateFrame("Frame", nil, detail)
|
||||
headIcon:SetSize(48, 48)
|
||||
headIcon:SetPoint("TOPLEFT", detail, "TOPLEFT", 0, 0)
|
||||
headIcon.tex = headIcon:CreateTexture(nil, "ARTWORK")
|
||||
headIcon.tex:SetPoint("TOPLEFT", headIcon, "TOPLEFT", 2, -2)
|
||||
headIcon.tex:SetPoint("BOTTOMRIGHT", headIcon, "BOTTOMRIGHT", -2, 2)
|
||||
headIcon.tex:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
||||
UI.AddBorder(headIcon, "gold", 1)
|
||||
|
||||
local nameLabel = UI.CreateLabel(detail, "", { font = "heading", size = 20, color = "goldLight" })
|
||||
nameLabel:SetPoint("TOPLEFT", detail, "TOPLEFT", 60, 0)
|
||||
nameLabel:SetWidth(380)
|
||||
nameLabel:SetWordWrap(false)
|
||||
|
||||
local subLabel = UI.CreateLabel(detail, "", { size = 12, color = "textDim" })
|
||||
subLabel:SetPoint("TOPLEFT", detail, "TOPLEFT", 60, -28)
|
||||
|
||||
local stateChip = UI.CreateChip(detail, "", "success")
|
||||
stateChip:SetPoint("TOPRIGHT", detail, "TOPRIGHT", 0, -4)
|
||||
|
||||
local updatedLabel = UI.CreateLabel(detail, "", { size = 11, color = "textDim", justify = "RIGHT" })
|
||||
updatedLabel:SetPoint("TOPRIGHT", detail, "TOPRIGHT", 0, -32)
|
||||
updatedLabel:SetWidth(240)
|
||||
|
||||
local headDivider = UI.CreateDivider(detail)
|
||||
headDivider:SetPoint("TOPLEFT", detail, "TOPLEFT", 0, -58)
|
||||
headDivider:SetPoint("TOPRIGHT", detail, "TOPRIGHT", 0, -58)
|
||||
|
||||
-- Kennzahlen
|
||||
local cards = {}
|
||||
local defs = {
|
||||
{ key = "happiness", label = L.PET_HAPPINESS },
|
||||
{ key = "loyalty", label = L.PET_LOYALTY },
|
||||
{ key = "training", label = L.PET_TRAINING },
|
||||
{ key = "health", label = L.PET_HEALTH },
|
||||
{ key = "damage", label = L.PET_DAMAGE },
|
||||
{ key = "armor", label = L.PET_ARMOR },
|
||||
{ key = "ap", label = L.PET_AP },
|
||||
{ key = "crit", label = L.PET_CRIT },
|
||||
{ key = "move", label = L.PET_MOVE },
|
||||
}
|
||||
for i, def in ipairs(defs) do
|
||||
local card = UI.CreateStatCard(detail, def.label, CARD_W, CARD_H)
|
||||
UI.SetFont(card.value, "heading", 13)
|
||||
local col = (i - 1) % 3
|
||||
local rowIndex = math.floor((i - 1) / 3)
|
||||
card:SetPoint("TOPLEFT", detail, "TOPLEFT", col * (CARD_W + CARD_GAP), -(68 + rowIndex * (CARD_H + CARD_GAP)))
|
||||
-- Familienfaktor oben rechts auf der Karte
|
||||
card.factor = UI.CreateLabel(card, "", { size = 10, color = "textDim", justify = "RIGHT", flags = "" })
|
||||
card.factor:SetPoint("TOPRIGHT", card, "TOPRIGHT", -10, -8)
|
||||
cards[def.key] = card
|
||||
end
|
||||
|
||||
-- Widerstaende (Schulen 2 bis 6)
|
||||
local RES_W, RES_GAP = 100, 12
|
||||
local resDefs = {
|
||||
{ school = 2, label = L.PET_RES_FIRE },
|
||||
{ school = 3, label = L.PET_RES_NATURE },
|
||||
{ school = 4, label = L.PET_RES_FROST },
|
||||
{ school = 5, label = L.PET_RES_SHADOW },
|
||||
{ school = 6, label = L.PET_RES_ARCANE },
|
||||
}
|
||||
local resCards = {}
|
||||
for i, def in ipairs(resDefs) do
|
||||
local card = UI.CreateStatCard(detail, def.label, RES_W, CARD_H)
|
||||
UI.SetFont(card.value, "heading", 13)
|
||||
card:SetPoint("TOPLEFT", detail, "TOPLEFT", (i - 1) * (RES_W + RES_GAP), -(68 + 3 * (CARD_H + CARD_GAP)))
|
||||
resCards[def.school] = card
|
||||
end
|
||||
|
||||
-- Tooltips: lesen den aktuell angezeigten Eintrag (current) beim Darueberfahren
|
||||
local current
|
||||
local function NoData()
|
||||
return { L.PET_TIP_NODATA }
|
||||
end
|
||||
local function ArmorReduction(armor, level)
|
||||
if type(PaperDollFrame_GetArmorReduction) == "function" then
|
||||
local ok, v = pcall(PaperDollFrame_GetArmorReduction, armor, level)
|
||||
if ok and type(v) == "number" then
|
||||
return v
|
||||
end
|
||||
end
|
||||
local r = armor / (armor + 400 + 85 * level) * 100
|
||||
return math.min(75, r)
|
||||
end
|
||||
local function TipLines(key)
|
||||
local rec = current
|
||||
local lines = {}
|
||||
if not rec then
|
||||
return NoData()
|
||||
end
|
||||
if key == "health" then
|
||||
lines = { L.PET_TIP_HEALTH_1, L.PET_TIP_HEALTH_2 }
|
||||
elseif key == "armor" then
|
||||
if not rec.armor then return NoData() end
|
||||
lines = { string.format(L.PET_TIP_ARMOR_1, ArmorReduction(rec.armor, rec.level or 1)), L.PET_TIP_ARMOR_2 }
|
||||
elseif key == "damage" then
|
||||
if not (rec.dmgMin and rec.dmgMax) then return NoData() end
|
||||
lines = { string.format(L.PET_TIP_DAMAGE_1, rec.dmgMin, rec.dmgMax) }
|
||||
if rec.speed and rec.speed > 0 then
|
||||
lines[#lines + 1] = string.format(L.PET_TIP_DAMAGE_2, rec.speed)
|
||||
lines[#lines + 1] = string.format(L.PET_TIP_DAMAGE_3, (rec.dmgMin + rec.dmgMax) / 2 / rec.speed)
|
||||
end
|
||||
elseif key == "ap" then
|
||||
if not rec.apBase then return NoData() end
|
||||
local bonus = rec.apBonus or 0
|
||||
lines = { string.format(L.PET_TIP_AP_1, rec.apBase, bonus, rec.apBase + bonus), L.PET_TIP_AP_2 }
|
||||
elseif key == "crit" then
|
||||
if not (rec.critMelee or rec.critSpell or rec.critRanged) then return NoData() end
|
||||
if rec.critMelee then lines[#lines + 1] = string.format(L.PET_TIP_CRIT_1, rec.critMelee) end
|
||||
if rec.critSpell then lines[#lines + 1] = string.format(L.PET_TIP_CRIT_2, rec.critSpell) end
|
||||
if rec.critRanged then lines[#lines + 1] = string.format(L.PET_TIP_CRIT_3, rec.critRanged) end
|
||||
lines[#lines + 1] = L.PET_TIP_CRIT_4
|
||||
elseif key == "move" then
|
||||
if not rec.runSpeed then return NoData() end
|
||||
lines = { string.format(L.PET_TIP_MOVE_1, rec.runSpeed, math.floor(rec.runSpeed / 7 * 100 + 0.5)) }
|
||||
end
|
||||
return lines
|
||||
end
|
||||
local tipTitles = {
|
||||
health = L.PET_TIP_HEALTH, armor = L.PET_TIP_ARMOR, damage = L.PET_TIP_DAMAGE,
|
||||
ap = L.PET_TIP_AP, crit = L.PET_TIP_CRIT, move = L.PET_TIP_MOVE,
|
||||
}
|
||||
for key, title in pairs(tipTitles) do local key = key
|
||||
UI.AttachTooltip(cards[key], title, function() return TipLines(key) end)
|
||||
end
|
||||
for school, card in pairs(resCards) do local school = school
|
||||
UI.AttachTooltip(card, L.PET_TIP_RES, function()
|
||||
local v = current and current.resist and current.resist[school]
|
||||
if not v then return NoData() end
|
||||
local pct = math.min(75, v / (math.max(1, current.level or 1) * 5) * 75)
|
||||
return { string.format(L.PET_TIP_RES_1, v), string.format(L.PET_TIP_RES_2, pct), L.PET_TIP_RES_3 }
|
||||
end)
|
||||
end
|
||||
|
||||
-- Faktor als Text und Farbe: ueber 1 gold, unter 1 gedaempft, 1,00 neutral
|
||||
local function SetFactor(card, factor)
|
||||
if not factor then
|
||||
card.factor:SetText("")
|
||||
return
|
||||
end
|
||||
local color = "textDim"
|
||||
if factor > 1.0001 then
|
||||
color = "goldLight"
|
||||
elseif factor < 0.9999 then
|
||||
color = "danger"
|
||||
end
|
||||
card.factor:SetText(string.format("x%.2f", factor))
|
||||
card.factor:SetTextColor(UI.Color(color))
|
||||
end
|
||||
|
||||
-- Nahrung
|
||||
local foodLabel = UI.CreateLabel(detail, L.PET_FOOD, { font = "heading", size = 13, color = "goldLight" })
|
||||
foodLabel:SetPoint("TOPLEFT", detail, "TOPLEFT", 0, -300)
|
||||
local foodNone = UI.CreateLabel(detail, L.PET_FOOD_UNKNOWN, { size = 12, color = "textDim" })
|
||||
foodNone:SetPoint("LEFT", foodLabel, "RIGHT", 14, 0)
|
||||
|
||||
-- Faehigkeiten
|
||||
local abilityTitle = UI.CreateLabel(detail, L.PET_ABILITIES, { font = "heading", size = 14, color = "goldLight" })
|
||||
abilityTitle:SetPoint("TOPLEFT", detail, "TOPLEFT", 0, -336)
|
||||
local abilityDivider = UI.CreateDivider(detail)
|
||||
abilityDivider:SetPoint("TOPLEFT", detail, "TOPLEFT", 0, -360)
|
||||
abilityDivider:SetPoint("TOPRIGHT", detail, "TOPRIGHT", 0, -360)
|
||||
|
||||
local abilityScroll = UI.CreateScrollFrame(detail)
|
||||
abilityScroll:SetPoint("TOPLEFT", detail, "TOPLEFT", 0, -368)
|
||||
abilityScroll:SetPoint("BOTTOMRIGHT", detail, "BOTTOMRIGHT", 0, 42)
|
||||
|
||||
local abilityNote = UI.CreateLabel(abilityScroll.child, "", { size = 11, color = "textDim" })
|
||||
|
||||
-- Knoepfe
|
||||
local status = UI.CreateLabel(detail, "", { size = 12 })
|
||||
status:SetWidth(360)
|
||||
|
||||
local refreshButton = UI.CreateButton(detail, L.PET_REFRESH, 170, 28, function()
|
||||
local ok, reason = Pet:Scan()
|
||||
if ok then
|
||||
status:SetText("|cff" .. UI.Hex("success") .. FW.L.PET_REFRESH_OK .. "|r")
|
||||
else
|
||||
local msg = FW.L.PET_REFRESH_FAIL
|
||||
if reason == "nopet" then
|
||||
msg = FW.L.PET_REFRESH_NOPET
|
||||
elseif reason == "combat" then
|
||||
msg = FW.L.PET_REFRESH_COMBAT
|
||||
elseif reason == "error" or reason == "nodata" then
|
||||
msg = FW.L.PET_REFRESH_ERROR
|
||||
end
|
||||
status:SetText("|cff" .. UI.Hex("danger") .. msg .. "|r")
|
||||
end
|
||||
end, "primary")
|
||||
refreshButton:SetPoint("BOTTOMLEFT", detail, "BOTTOMLEFT", 0, 0)
|
||||
|
||||
local confirming = false
|
||||
local deleteButton
|
||||
deleteButton = UI.CreateButton(detail, L.PET_DELETE, 160, 28, function()
|
||||
if confirming then
|
||||
confirming = false
|
||||
deleteButton:SetLabel(FW.L.PET_DELETE)
|
||||
deleteButton:SetStyle("danger")
|
||||
if Pet.selectedKey then
|
||||
Pet:Delete(Pet.selectedKey)
|
||||
end
|
||||
else
|
||||
confirming = true
|
||||
deleteButton:SetLabel(FW.L.PET_DELETE_CONFIRM)
|
||||
deleteButton:SetStyle("dangerActive")
|
||||
C_Timer.After(3, function()
|
||||
confirming = false
|
||||
deleteButton:SetLabel(FW.L.PET_DELETE)
|
||||
deleteButton:SetStyle("danger")
|
||||
end)
|
||||
end
|
||||
end, "danger")
|
||||
deleteButton:SetPoint("LEFT", refreshButton, "RIGHT", 8, 0)
|
||||
|
||||
status:SetPoint("LEFT", deleteButton, "RIGHT", 16, 0)
|
||||
|
||||
---------------- Inhalt fuellen ----------------
|
||||
local HAPPINESS = {
|
||||
[3] = { text = function() return FW.L.PET_HAPPY end, color = "success" },
|
||||
[2] = { text = function() return FW.L.PET_CONTENT end, color = "goldLight" },
|
||||
[1] = { text = function() return FW.L.PET_UNHAPPY end, color = "danger" },
|
||||
}
|
||||
|
||||
local function ShowFoods(foods)
|
||||
for _, chip in ipairs(foodChips) do
|
||||
chip:Hide()
|
||||
end
|
||||
if type(foods) ~= "table" or #foods == 0 then
|
||||
foodNone:Show()
|
||||
return
|
||||
end
|
||||
foodNone:Hide()
|
||||
local previous
|
||||
for i, food in ipairs(foods) do
|
||||
local chip = foodChips[i]
|
||||
if not chip then
|
||||
chip = UI.CreateChip(detail, food, "bronze")
|
||||
foodChips[i] = chip
|
||||
end
|
||||
chip:SetText(food, "goldAntique")
|
||||
chip:ClearAllPoints()
|
||||
if previous then
|
||||
chip:SetPoint("LEFT", previous, "RIGHT", 6, 0)
|
||||
else
|
||||
chip:SetPoint("LEFT", foodLabel, "RIGHT", 14, 0)
|
||||
end
|
||||
chip:Show()
|
||||
previous = chip
|
||||
end
|
||||
end
|
||||
|
||||
local function ShowAbilities(rec)
|
||||
local list = rec.abilities or {}
|
||||
local others = rec.others or {}
|
||||
|
||||
for i, ability in ipairs(list) do
|
||||
local row = abilityRows[i]
|
||||
if not row then
|
||||
row = UI.CreatePanel(abilityScroll.child, "card", "bronze")
|
||||
row:SetHeight(ABILITY_H)
|
||||
row.icon = row:CreateTexture(nil, "ARTWORK")
|
||||
row.icon:SetSize(ABILITY_H - 8, ABILITY_H - 8)
|
||||
row.icon:SetPoint("LEFT", row, "LEFT", 5, 0)
|
||||
row.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
||||
row.name = UI.CreateLabel(row, "", { size = 12 })
|
||||
row.name:SetPoint("LEFT", row.icon, "RIGHT", 8, 0)
|
||||
row.passive = UI.CreateLabel(row, "", { size = 10, color = "textDim", justify = "RIGHT" })
|
||||
row.chip = UI.CreateChip(row, "", "goldLight")
|
||||
row.chip:SetPoint("RIGHT", row, "RIGHT", -6, 0)
|
||||
row.passive:SetPoint("RIGHT", row.chip, "LEFT", -8, 0)
|
||||
abilityRows[i] = row
|
||||
end
|
||||
local y = (i - 1) * (ABILITY_H + 4)
|
||||
row:ClearAllPoints()
|
||||
row:SetPoint("TOPLEFT", abilityScroll.child, "TOPLEFT", 0, -y)
|
||||
row:SetPoint("TOPRIGHT", abilityScroll.child, "TOPRIGHT", 0, -y)
|
||||
row.name:SetText(ability.name or "?")
|
||||
local tex
|
||||
if ability.spellID then
|
||||
if C_Spell and C_Spell.GetSpellTexture then
|
||||
local ok, t = pcall(C_Spell.GetSpellTexture, ability.spellID)
|
||||
tex = ok and t or nil
|
||||
elseif GetSpellTexture then
|
||||
local ok, t = pcall(GetSpellTexture, ability.spellID)
|
||||
tex = ok and t or nil
|
||||
end
|
||||
end
|
||||
row.icon:SetTexture(tex or "Interface\\Icons\\INV_Misc_QuestionMark")
|
||||
row.passive:SetText(ability.passive and FW.L.PET_PASSIVE or "")
|
||||
if ability.rank then
|
||||
row.chip:SetText(string.format(FW.L.PET_RANK, ability.rank), "goldLight")
|
||||
row.chip:Show()
|
||||
else
|
||||
row.chip:Hide()
|
||||
end
|
||||
row:Show()
|
||||
end
|
||||
for i = #list + 1, #abilityRows do
|
||||
abilityRows[i]:Hide()
|
||||
end
|
||||
|
||||
local y = #list * (ABILITY_H + 4)
|
||||
local noteText
|
||||
if #list == 0 then
|
||||
noteText = FW.L.PET_NO_ABILITIES
|
||||
elseif #others > 0 then
|
||||
noteText = string.format(FW.L.PET_OTHERS, #others)
|
||||
end
|
||||
abilityNote:ClearAllPoints()
|
||||
abilityNote:SetPoint("TOPLEFT", abilityScroll.child, "TOPLEFT", 4, -(y + 6))
|
||||
abilityNote:SetText(noteText or "")
|
||||
abilityScroll:SetContentHeight(y + 30)
|
||||
end
|
||||
|
||||
local function ShowRecord(key, rec)
|
||||
current = rec
|
||||
local L2 = FW.L
|
||||
nameLabel:SetText(rec.name or "?")
|
||||
headIcon.tex:SetTexture(Pet.FamilyIcon and Pet.FamilyIcon(rec.family) or "Interface\\Icons\\Ability_Hunter_BeastTaming")
|
||||
subLabel:SetText(Subtitle(rec))
|
||||
updatedLabel:SetText(string.format(L2.PET_UPDATED, FormatTime(rec.updated or rec.importedAt)))
|
||||
|
||||
if key == Pet.activeKey then
|
||||
stateChip:SetText(L2.PET_ACTIVE, "success")
|
||||
stateChip:Show()
|
||||
elseif rec.src == "import" then
|
||||
stateChip:SetText(L2.PET_IMPORTED, "textDim")
|
||||
stateChip:Show()
|
||||
else
|
||||
stateChip:Hide()
|
||||
end
|
||||
|
||||
-- Zufriedenheit
|
||||
local happy = HAPPINESS[rec.happiness or 0]
|
||||
if happy then
|
||||
local text = happy.text()
|
||||
if rec.damagePct then
|
||||
text = string.format("%s (%d%%)", text, rec.damagePct)
|
||||
end
|
||||
cards.happiness:SetValue(text, happy.color)
|
||||
else
|
||||
cards.happiness:SetValue("-", "textDim")
|
||||
end
|
||||
|
||||
-- Treue
|
||||
if rec.loyaltyText then
|
||||
local plain = rec.loyaltyText:gsub("^%b()%s*", "")
|
||||
local text = plain ~= "" and plain or rec.loyaltyText
|
||||
if rec.loyaltyLevel then
|
||||
text = rec.loyaltyLevel .. " - " .. text
|
||||
end
|
||||
cards.loyalty:SetValue(text)
|
||||
else
|
||||
cards.loyalty:SetValue("-", "textDim")
|
||||
end
|
||||
|
||||
-- Trainingspunkte
|
||||
if rec.trainingTotal then
|
||||
local free = math.max(0, rec.trainingTotal - (rec.trainingSpent or 0))
|
||||
cards.training:SetValue(string.format(L2.PET_TRAINING_VALUE, free, rec.trainingTotal))
|
||||
else
|
||||
cards.training:SetValue("-", "textDim")
|
||||
end
|
||||
|
||||
-- Leben, Schaden (mit Tempo im Titel), Ruestung, dazu die Familienfaktoren
|
||||
local mods = Pet.GetFamilyMods and Pet.GetFamilyMods(rec.family)
|
||||
if rec.hpMax then
|
||||
cards.health:SetValue(string.format("%d", rec.hpMax))
|
||||
else
|
||||
cards.health:SetValue("-", "textDim")
|
||||
end
|
||||
SetFactor(cards.health, mods and mods.hp)
|
||||
if rec.dmgMin and rec.dmgMax then
|
||||
cards.damage:SetValue(string.format("%d - %d", rec.dmgMin, rec.dmgMax))
|
||||
else
|
||||
cards.damage:SetValue("-", "textDim")
|
||||
end
|
||||
if rec.speed then
|
||||
cards.damage:SetLabel(string.format("%s | %.1f s", L2.PET_DAMAGE, rec.speed))
|
||||
else
|
||||
cards.damage:SetLabel(L2.PET_DAMAGE)
|
||||
end
|
||||
SetFactor(cards.damage, mods and mods.dmg)
|
||||
SetFactor(cards.armor, mods and mods.armor)
|
||||
if rec.armor then
|
||||
cards.armor:SetValue(string.format("%d", rec.armor))
|
||||
else
|
||||
cards.armor:SetValue("-", "textDim")
|
||||
end
|
||||
|
||||
-- Zusatzwerte
|
||||
if rec.apBase then
|
||||
cards.ap:SetValue(string.format("%d", rec.apBase + (rec.apBonus or 0)))
|
||||
else
|
||||
cards.ap:SetValue("-", "textDim")
|
||||
end
|
||||
local crit = rec.critRanged or rec.critMelee
|
||||
if crit then
|
||||
cards.crit:SetValue(string.format("%.2f%%", crit))
|
||||
else
|
||||
cards.crit:SetValue("-", "textDim")
|
||||
end
|
||||
if rec.runSpeed then
|
||||
cards.move:SetValue(string.format("%d%%", math.floor(rec.runSpeed / 7 * 100 + 0.5)))
|
||||
else
|
||||
cards.move:SetValue("-", "textDim")
|
||||
end
|
||||
for school, card in pairs(resCards) do
|
||||
local v = rec.resist and rec.resist[school]
|
||||
if v then
|
||||
card:SetValue(string.format("%d", v))
|
||||
else
|
||||
card:SetValue("-", "textDim")
|
||||
end
|
||||
end
|
||||
|
||||
ShowFoods(rec.foods)
|
||||
ShowAbilities(rec)
|
||||
end
|
||||
|
||||
function f.Refresh()
|
||||
local keys = SortedKeys()
|
||||
|
||||
if not Pet.selectedKey or not Pet.db.pets[Pet.selectedKey] then
|
||||
Pet.selectedKey = (Pet.activeKey and Pet.db.pets[Pet.activeKey]) and Pet.activeKey or keys[1]
|
||||
end
|
||||
|
||||
for i, key in ipairs(keys) do
|
||||
local rec = Pet.db.pets[key]
|
||||
local row = rows[i]
|
||||
if not row then
|
||||
row = CreateListRow(listScroll.child, function(selectedKey)
|
||||
Pet.selectedKey = selectedKey
|
||||
f.Refresh()
|
||||
end)
|
||||
rows[i] = row
|
||||
end
|
||||
row.key = key
|
||||
local y = (i - 1) * (ROW_H + ROW_GAP)
|
||||
row:ClearAllPoints()
|
||||
row:SetPoint("TOPLEFT", listScroll.child, "TOPLEFT", 0, -y)
|
||||
row:SetPoint("TOPRIGHT", listScroll.child, "TOPRIGHT", 0, -y)
|
||||
row.name:SetText(rec.name or "?")
|
||||
row.icon:SetTexture(Pet.FamilyIcon and Pet.FamilyIcon(rec.family) or "Interface\\Icons\\Ability_Hunter_BeastTaming")
|
||||
row.sub:SetText(Subtitle(rec))
|
||||
if key == Pet.activeKey then
|
||||
row.chip:SetText(FW.L.PET_ACTIVE, "success")
|
||||
row.chip:Show()
|
||||
elseif rec.src == "import" then
|
||||
row.chip:SetText(FW.L.PET_IMPORTED, "textDim")
|
||||
row.chip:Show()
|
||||
else
|
||||
row.chip:Hide()
|
||||
end
|
||||
row:SetSelected(key == Pet.selectedKey)
|
||||
row:Show()
|
||||
end
|
||||
for i = #keys + 1, #rows do
|
||||
rows[i]:Hide()
|
||||
end
|
||||
listScroll:SetContentHeight(#keys * (ROW_H + ROW_GAP))
|
||||
|
||||
local rec = Pet.selectedKey and Pet.db.pets[Pet.selectedKey]
|
||||
if rec then
|
||||
empty:Hide()
|
||||
detail:Show()
|
||||
ShowRecord(Pet.selectedKey, rec)
|
||||
refreshButton:SetButtonEnabled(UnitExists("pet") and true or false)
|
||||
else
|
||||
detail:Hide()
|
||||
empty:Show()
|
||||
end
|
||||
end
|
||||
|
||||
FW:On("PET_UPDATED", function()
|
||||
if f:IsVisible() then
|
||||
f.Refresh()
|
||||
end
|
||||
end)
|
||||
|
||||
f.Refresh()
|
||||
return f
|
||||
end
|
||||
|
||||
UI:RegisterTab("pet", {
|
||||
label = function()
|
||||
return FW.L.PET_TAB
|
||||
end,
|
||||
order = 60,
|
||||
build = Build,
|
||||
onShow = function(f)
|
||||
f.Refresh()
|
||||
end,
|
||||
})
|
||||
|
||||
SLASH_FREEWOODPET1 = "/fwpet"
|
||||
SlashCmdList["FREEWOODPET"] = function()
|
||||
UI:Toggle("pet")
|
||||
end
|
||||
Reference in New Issue
Block a user