1123 lines
39 KiB
Lua
1123 lines
39 KiB
Lua
-- Freewood-OctoWoW-Beasts: Tab "Wildtiere"
|
|
-- Links Suche, Filter und Liste, rechts Familienfaktoren, Nahrung, Fundorte und Faehigkeiten.
|
|
|
|
local ADDON, NS = ...
|
|
|
|
local FW = _G.Freewood
|
|
local Beasts = NS.Beasts
|
|
if not FW or not Beasts then
|
|
return
|
|
end
|
|
|
|
local UI = FW.UI
|
|
local Pet = FW.Pet
|
|
|
|
local LIST_W = 300
|
|
local ROW_H, ROW_GAP = 50, 6
|
|
local CARD_W, CARD_H, CARD_GAP = 170, 48, 10
|
|
local ITEM_H = 24
|
|
|
|
local FAMILY_ICON = {
|
|
bat = "Ability_Hunter_Pet_Bat", bear = "Ability_Hunter_Pet_Bear", boar = "Ability_Hunter_Pet_Boar",
|
|
carrionbird = "Ability_Hunter_Pet_Vulture", cat = "Ability_Hunter_Pet_Cat", crab = "Ability_Hunter_Pet_Crab",
|
|
crocolisk = "Ability_Hunter_Pet_Crocolisk", gorilla = "Ability_Hunter_Pet_Gorilla",
|
|
hyena = "Ability_Hunter_Pet_Hyena", owl = "Ability_Hunter_Pet_Owl", raptor = "Ability_Hunter_Pet_Raptor",
|
|
scorpid = "Ability_Hunter_Pet_Scorpid", spider = "Ability_Hunter_Pet_Spider",
|
|
tallstrider = "Ability_Hunter_Pet_TallStrider", turtle = "Ability_Hunter_Pet_Turtle",
|
|
windserpent = "Ability_Hunter_Pet_WindSerpent", wolf = "Ability_Hunter_Pet_Wolf",
|
|
}
|
|
|
|
local function FamilyIcon(fid)
|
|
return "Interface\\Icons\\" .. (FAMILY_ICON[fid] or "Ability_Hunter_BeastTaming")
|
|
end
|
|
|
|
local STATUS_COLOR = { tamed = "success", lored = "goldLight", seen = "text", unknown = "textDim" }
|
|
|
|
local function StatusText(status)
|
|
local L = FW.L
|
|
if status == "tamed" then return L.BEAST_STATUS_TAMED end
|
|
if status == "lored" then return L.BEAST_STATUS_LORED end
|
|
if status == "seen" then return L.BEAST_STATUS_SEEN end
|
|
return L.BEAST_STATUS_UNKNOWN
|
|
end
|
|
|
|
local function LevelText(s)
|
|
local L = FW.L
|
|
if not s.lvl1 then
|
|
return nil
|
|
end
|
|
local range = (s.lvl2 and s.lvl2 ~= s.lvl1) and (s.lvl1 .. "-" .. s.lvl2) or tostring(s.lvl1)
|
|
local text = string.format(L.BEAST_LEVEL, range)
|
|
if s.c == "elite" then
|
|
text = text .. " " .. L.BEAST_ELITE
|
|
elseif s.c == "rare" then
|
|
text = text .. " " .. L.BEAST_RARE
|
|
elseif s.c == "rareelite" then
|
|
text = text .. " " .. L.BEAST_RAREELITE
|
|
elseif s.c == "worldboss" then
|
|
text = text .. " " .. L.BEAST_BOSS
|
|
elseif type(s.c) == "string" and s.c ~= "" then
|
|
local key = string.lower(s.c)
|
|
if key == "rare" then text = text .. " " .. L.BEAST_RARE end
|
|
end
|
|
return text
|
|
end
|
|
|
|
local function Subtitle(s)
|
|
local parts = { s.family or FW.L.BEAST_FAMILY_UNKNOWN }
|
|
local lvl = LevelText(s)
|
|
if lvl then
|
|
parts[#parts + 1] = lvl
|
|
end
|
|
if s.zone then
|
|
parts[#parts + 1] = s.zone
|
|
end
|
|
return table.concat(parts, " - ")
|
|
end
|
|
|
|
local function FoodList(codes)
|
|
local out = {}
|
|
if type(codes) == "string" then
|
|
for i = 1, #codes do
|
|
local c = codes:sub(i, i)
|
|
out[#out + 1] = FW.L["BEAST_FOOD_" .. c] or c
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
|
|
local function SpellName(spellID)
|
|
if C_Spell and C_Spell.GetSpellInfo then
|
|
local ok, info = pcall(C_Spell.GetSpellInfo, spellID)
|
|
if ok and type(info) == "table" and info.name then
|
|
return info.name
|
|
end
|
|
end
|
|
return "Spell " .. tostring(spellID)
|
|
end
|
|
|
|
local function SpellRank(spellID)
|
|
if C_Spell and C_Spell.GetSpellSubtext then
|
|
local ok, text = pcall(C_Spell.GetSpellSubtext, spellID)
|
|
if ok and type(text) == "string" and text ~= "" then
|
|
return text
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Auswahlliste (Dropdown)
|
|
------------------------------------------------------------------------
|
|
|
|
local popup
|
|
|
|
local function ClosePopup()
|
|
if popup then
|
|
popup:Hide()
|
|
popup.owner = nil
|
|
end
|
|
end
|
|
|
|
local function GetPopup()
|
|
if popup then
|
|
return popup
|
|
end
|
|
popup = UI.CreatePanel(UIParent, "bgDeep", "gold")
|
|
popup:SetFrameStrata("FULLSCREEN_DIALOG")
|
|
popup:SetClampedToScreen(true)
|
|
popup:EnableMouse(true)
|
|
popup.scroll = UI.CreateScrollFrame(popup)
|
|
popup.scroll:SetPoint("TOPLEFT", popup, "TOPLEFT", 3, -3)
|
|
popup.scroll:SetPoint("BOTTOMRIGHT", popup, "BOTTOMRIGHT", -3, 3)
|
|
popup.items = {}
|
|
popup:Hide()
|
|
return popup
|
|
end
|
|
|
|
local function OpenPopup(anchor, options, currentKey, onPick)
|
|
local p = GetPopup()
|
|
if p:IsShown() and p.owner == anchor then
|
|
ClosePopup()
|
|
return
|
|
end
|
|
p.owner = anchor
|
|
for i, opt in ipairs(options) do
|
|
local item = p.items[i]
|
|
if not item then
|
|
item = CreateFrame("Button", nil, p.scroll.child)
|
|
item:SetHeight(ITEM_H)
|
|
item.bg = item:CreateTexture(nil, "BACKGROUND")
|
|
item.bg:SetAllPoints()
|
|
item.label = UI.CreateLabel(item, "", { size = 12 })
|
|
item.label:SetPoint("LEFT", item, "LEFT", 8, 0)
|
|
item.label:SetPoint("RIGHT", item, "RIGHT", -8, 0)
|
|
item.label:SetWordWrap(false)
|
|
item:SetScript("OnEnter", function(self)
|
|
self.bg:SetColorTexture(UI.Color("hover"))
|
|
end)
|
|
item:SetScript("OnLeave", function(self)
|
|
self.bg:SetColorTexture(UI.Color(self.active and "card" or "bgDeep"))
|
|
end)
|
|
item:SetScript("OnClick", function(self)
|
|
local cb = p.onPick
|
|
ClosePopup()
|
|
if cb then
|
|
cb(self.key)
|
|
end
|
|
end)
|
|
p.items[i] = item
|
|
end
|
|
item.key = opt.key
|
|
item.active = (opt.key == currentKey)
|
|
item.bg:SetColorTexture(UI.Color(item.active and "card" or "bgDeep"))
|
|
item.label:SetText(opt.text)
|
|
item.label:SetTextColor(UI.Color(item.active and "goldLight" or "text"))
|
|
item:ClearAllPoints()
|
|
item:SetPoint("TOPLEFT", p.scroll.child, "TOPLEFT", 0, -(i - 1) * ITEM_H)
|
|
item:SetPoint("TOPRIGHT", p.scroll.child, "TOPRIGHT", 0, -(i - 1) * ITEM_H)
|
|
item:Show()
|
|
end
|
|
for i = #options + 1, #p.items do
|
|
p.items[i]:Hide()
|
|
end
|
|
p.onPick = onPick
|
|
p.scroll:SetContentHeight(#options * ITEM_H)
|
|
p.scroll:ScrollToTop()
|
|
|
|
p:SetScale((anchor:GetEffectiveScale() or 1) / (UIParent:GetEffectiveScale() or 1))
|
|
p:SetSize(math.max(anchor:GetWidth() or 150, 190), math.min(#options * ITEM_H + 6, 270))
|
|
p:ClearAllPoints()
|
|
p:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -2)
|
|
p:Show()
|
|
end
|
|
|
|
local function CreateSelect(parent, width, getOptions, getKey, onPick)
|
|
local button
|
|
button = UI.CreateButton(parent, "", width, 24, function()
|
|
OpenPopup(button, getOptions(), getKey(), function(key)
|
|
onPick(key)
|
|
end)
|
|
end, "default")
|
|
button.label:ClearAllPoints()
|
|
button.label:SetPoint("LEFT", button, "LEFT", 8, 0)
|
|
button.label:SetPoint("RIGHT", button, "RIGHT", -8, 0)
|
|
button.label:SetJustifyH("LEFT")
|
|
button.label:SetWordWrap(false)
|
|
return button
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Suchfeld
|
|
------------------------------------------------------------------------
|
|
|
|
local function CreateSearchBox(parent, width, placeholder, onChange)
|
|
local box = UI.CreatePanel(parent, "bgDeep", "bronze")
|
|
box:SetSize(width, 26)
|
|
local edit = CreateFrame("EditBox", nil, box)
|
|
edit:SetAutoFocus(false)
|
|
edit:SetPoint("TOPLEFT", box, "TOPLEFT", 8, -2)
|
|
edit:SetPoint("BOTTOMRIGHT", box, "BOTTOMRIGHT", -8, 2)
|
|
edit:SetMaxLetters(48)
|
|
if not edit:SetFont(UI.GetFontPath("body"), 12, "") then
|
|
edit:SetFont("Fonts\\FRIZQT__.TTF", 12, "")
|
|
end
|
|
edit:SetTextColor(UI.Color("text"))
|
|
local hint = UI.CreateLabel(box, placeholder, { size = 12, color = "textDim" })
|
|
hint:SetPoint("LEFT", box, "LEFT", 10, 0)
|
|
local function Sync()
|
|
if (edit:GetText() or "") == "" then
|
|
hint:Show()
|
|
else
|
|
hint:Hide()
|
|
end
|
|
end
|
|
edit:SetScript("OnTextChanged", function()
|
|
Sync()
|
|
onChange(edit:GetText() or "")
|
|
end)
|
|
edit:SetScript("OnEscapePressed", function(self)
|
|
self:ClearFocus()
|
|
end)
|
|
edit:SetScript("OnEditFocusGained", function()
|
|
UI.SetBorderColor(box, "gold")
|
|
end)
|
|
edit:SetScript("OnEditFocusLost", function()
|
|
UI.SetBorderColor(box, "bronze")
|
|
end)
|
|
box.edit = edit
|
|
Sync()
|
|
return box
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Listenzeile
|
|
------------------------------------------------------------------------
|
|
|
|
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 - 150)
|
|
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 - 76)
|
|
row.sub:SetWordWrap(false)
|
|
|
|
row.chip = UI.CreateChip(row, "", "textDim")
|
|
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.id)
|
|
end)
|
|
Refresh()
|
|
return row
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Stapel im Detailbereich (wiederverwendete Bausteine)
|
|
------------------------------------------------------------------------
|
|
|
|
local function NewStack(scroll)
|
|
local s = { child = scroll.child, y = 0, pool = { label = {}, row = {}, chip = {} }, used = { label = 0, row = 0, chip = 0 } }
|
|
|
|
local function take(kind, create)
|
|
s.used[kind] = s.used[kind] + 1
|
|
local item = s.pool[kind][s.used[kind]]
|
|
if not item then
|
|
item = create()
|
|
s.pool[kind][s.used[kind]] = item
|
|
end
|
|
item:Show()
|
|
return item
|
|
end
|
|
|
|
function s:Reset()
|
|
for kind, list in pairs(self.pool) do
|
|
for _, item in ipairs(list) do
|
|
item:Hide()
|
|
end
|
|
self.used[kind] = 0
|
|
end
|
|
self.y = 0
|
|
end
|
|
|
|
function s:Gap(h)
|
|
self.y = self.y + h
|
|
end
|
|
|
|
function s:Heading(text)
|
|
local fs = take("label", function()
|
|
return UI.CreateLabel(self.child, "", { size = 12 })
|
|
end)
|
|
UI.SetFont(fs, "heading", 14)
|
|
fs:SetTextColor(UI.Color("goldLight"))
|
|
fs:SetWordWrap(false)
|
|
fs:ClearAllPoints()
|
|
fs:SetPoint("TOPLEFT", self.child, "TOPLEFT", 0, -self.y)
|
|
fs:SetPoint("TOPRIGHT", self.child, "TOPRIGHT", 0, -self.y)
|
|
fs:SetHeight(20)
|
|
fs:SetText(text)
|
|
self.y = self.y + 24
|
|
end
|
|
|
|
function s:Text(text, colorKey)
|
|
local fs = take("label", function()
|
|
return UI.CreateLabel(self.child, "", { size = 12 })
|
|
end)
|
|
UI.SetFont(fs, "body", 12)
|
|
fs:SetTextColor(UI.Color(colorKey or "textDim"))
|
|
fs:SetWordWrap(true)
|
|
fs:SetJustifyV("TOP")
|
|
fs:ClearAllPoints()
|
|
fs:SetPoint("TOPLEFT", self.child, "TOPLEFT", 0, -self.y)
|
|
fs:SetPoint("TOPRIGHT", self.child, "TOPRIGHT", 0, -self.y)
|
|
local lines = math.max(1, math.ceil(#text / 75))
|
|
fs:SetHeight(lines * 15)
|
|
fs:SetText(text)
|
|
self.y = self.y + lines * 15 + 4
|
|
end
|
|
|
|
-- Marken nebeneinander (einzeilig, bricht bei Bedarf um)
|
|
function s:Chips(list, colorKey)
|
|
local x, rowY = 0, self.y
|
|
for _, text in ipairs(list) do
|
|
local chip = take("chip", function()
|
|
return UI.CreateChip(self.child, "", "bronze")
|
|
end)
|
|
chip:SetText(text, colorKey or "goldAntique")
|
|
local w = chip:GetWidth() or 60
|
|
if x > 0 and x + w > 500 then
|
|
x = 0
|
|
rowY = rowY + 26
|
|
end
|
|
chip:ClearAllPoints()
|
|
chip:SetPoint("TOPLEFT", self.child, "TOPLEFT", x, -rowY)
|
|
x = x + w + 6
|
|
end
|
|
self.y = rowY + 28
|
|
end
|
|
|
|
-- Zeile: links Text, rechts Text oder Marke; optional klickbar
|
|
function s:Row(left, right, rightColor, onClick, selected)
|
|
local row = take("row", function()
|
|
local r = CreateFrame("Button", nil, self.child)
|
|
r:SetHeight(26)
|
|
r.bg = r:CreateTexture(nil, "BACKGROUND")
|
|
r.bg:SetAllPoints()
|
|
UI.AddBorder(r, "bronze", 0.6)
|
|
r.left = UI.CreateLabel(r, "", { size = 12 })
|
|
r.left:SetPoint("LEFT", r, "LEFT", 10, 0)
|
|
r.left:SetWordWrap(false)
|
|
r.right = UI.CreateLabel(r, "", { size = 11, color = "textDim", justify = "RIGHT" })
|
|
r.right:SetPoint("RIGHT", r, "RIGHT", -10, 0)
|
|
r.right:SetWordWrap(false)
|
|
r.left:SetPoint("RIGHT", r.right, "LEFT", -8, 0)
|
|
local function paint()
|
|
if r.selected then
|
|
r.bg:SetColorTexture(UI.Color("hover"))
|
|
UI.SetBorderColor(r, "gold")
|
|
elseif r.hover and r.clickable then
|
|
r.bg:SetColorTexture(UI.Color("hover", 0.7))
|
|
UI.SetBorderColor(r, "bronze")
|
|
else
|
|
r.bg:SetColorTexture(UI.Color("card"))
|
|
UI.SetBorderColor(r, "bronze", 0.6)
|
|
end
|
|
end
|
|
r.paint = paint
|
|
r:SetScript("OnEnter", function()
|
|
r.hover = true
|
|
paint()
|
|
end)
|
|
r:SetScript("OnLeave", function()
|
|
r.hover = false
|
|
paint()
|
|
end)
|
|
r:SetScript("OnClick", function()
|
|
if r.onClick then
|
|
r.onClick()
|
|
end
|
|
end)
|
|
return r
|
|
end)
|
|
row.onClick = onClick
|
|
row.clickable = onClick ~= nil
|
|
row.selected = selected and true or false
|
|
row.left:SetText(left or "")
|
|
row.right:SetText(right or "")
|
|
row.right:SetTextColor(UI.Color(rightColor or "textDim"))
|
|
row:ClearAllPoints()
|
|
row:SetPoint("TOPLEFT", self.child, "TOPLEFT", 0, -self.y)
|
|
row:SetPoint("TOPRIGHT", self.child, "TOPRIGHT", 0, -self.y)
|
|
row.paint()
|
|
self.y = self.y + 30
|
|
return row
|
|
end
|
|
|
|
function s:Height()
|
|
return self.y
|
|
end
|
|
|
|
return s
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Tab
|
|
------------------------------------------------------------------------
|
|
|
|
local function FactorColor(f)
|
|
if f > 1.0001 then
|
|
return "goldLight"
|
|
elseif f < 0.9999 then
|
|
return "danger"
|
|
end
|
|
return "text"
|
|
end
|
|
|
|
local function Build(content)
|
|
local L = FW.L
|
|
local f = CreateFrame("Frame", nil, content)
|
|
|
|
local rows = {}
|
|
local filter = { text = "", fid = nil, zone = nil, status = nil, ability = nil, rank = nil, rankMin = false }
|
|
local selectedGroup
|
|
|
|
---------------- linke Spalte ----------------
|
|
local title = UI.CreateLabel(f, L.BEAST_TITLE, { font = "heading", size = 14, color = "goldLight" })
|
|
title:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
|
|
local countLabel = UI.CreateLabel(f, "", { size = 11, color = "textDim", justify = "RIGHT" })
|
|
countLabel:SetPoint("TOPRIGHT", f, "TOPLEFT", LIST_W, 0)
|
|
countLabel:SetWidth(LIST_W - 90)
|
|
countLabel:SetWordWrap(false)
|
|
|
|
local listDivider = UI.CreateDivider(f)
|
|
listDivider:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -26)
|
|
listDivider:SetWidth(LIST_W)
|
|
|
|
local search = CreateSearchBox(f, LIST_W, L.BEAST_SEARCH, function(text)
|
|
filter.text = text
|
|
if f.Refresh then f.Refresh() end
|
|
end)
|
|
search:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -36)
|
|
|
|
local familySelect, zoneSelect
|
|
familySelect = CreateSelect(f, 146, function()
|
|
local fams = Beasts:FilterChoices()
|
|
local opts = { { key = false, text = FW.L.BEAST_ALL_FAMILIES } }
|
|
for _, fam in ipairs(fams) do
|
|
opts[#opts + 1] = { key = fam.id, text = fam.text }
|
|
end
|
|
return opts
|
|
end, function()
|
|
return filter.fid or false
|
|
end, function(key)
|
|
filter.fid = key or nil
|
|
if f.Refresh then f.Refresh() end
|
|
end)
|
|
familySelect:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -68)
|
|
|
|
zoneSelect = CreateSelect(f, 146, function()
|
|
local _, zones = Beasts:FilterChoices()
|
|
local opts = { { key = false, text = FW.L.BEAST_ALL_ZONES } }
|
|
for _, z in ipairs(zones) do
|
|
opts[#opts + 1] = { key = z, text = z }
|
|
end
|
|
return opts
|
|
end, function()
|
|
return filter.zone or false
|
|
end, function(key)
|
|
filter.zone = key or nil
|
|
if f.Refresh then f.Refresh() end
|
|
end)
|
|
zoneSelect:SetPoint("TOPLEFT", f, "TOPLEFT", 154, -68)
|
|
|
|
-- Faehigkeit, die das Zaehmen lehrt (und Rang)
|
|
local abilitySelect, rankSelect
|
|
abilitySelect = CreateSelect(f, 186, function()
|
|
local opts = { { key = false, text = FW.L.BEAST_ALL_ABILITIES } }
|
|
for _, name in ipairs(Beasts:AbilityChoices()) do
|
|
opts[#opts + 1] = { key = name, text = name }
|
|
end
|
|
return opts
|
|
end, function()
|
|
return filter.ability or false
|
|
end, function(key)
|
|
filter.ability = key or nil
|
|
filter.rank, filter.rankMin = nil, false
|
|
if f.Refresh then f.Refresh() end
|
|
end)
|
|
abilitySelect:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -98)
|
|
|
|
rankSelect = CreateSelect(f, 108, function()
|
|
local opts = { { key = false, text = FW.L.BEAST_ALL_RANKS } }
|
|
if filter.ability then
|
|
local ranks = Beasts:AbilityRanks(filter.ability)
|
|
for _, r in ipairs(ranks) do
|
|
opts[#opts + 1] = { key = r, text = string.format(FW.L.BEAST_RANK_EXACT, r) }
|
|
end
|
|
for i, r in ipairs(ranks) do
|
|
if i > 1 then
|
|
opts[#opts + 1] = { key = -r, text = string.format(FW.L.BEAST_RANK_MIN, r) }
|
|
end
|
|
end
|
|
end
|
|
return opts
|
|
end, function()
|
|
if not filter.rank then
|
|
return false
|
|
end
|
|
return filter.rankMin and -filter.rank or filter.rank
|
|
end, function(key)
|
|
if key then
|
|
filter.rank, filter.rankMin = math.abs(key), key < 0
|
|
else
|
|
filter.rank, filter.rankMin = nil, false
|
|
end
|
|
if f.Refresh then f.Refresh() end
|
|
end)
|
|
rankSelect:SetPoint("TOPLEFT", f, "TOPLEFT", 192, -98)
|
|
|
|
-- Statusfilter
|
|
local statusButtons = {}
|
|
local statusDefs = {
|
|
{ key = false, text = function() return FW.L.BEAST_STATUS_ALL end, w = 44 },
|
|
{ key = "seen", text = function() return FW.L.BEAST_STATUS_SEEN end, w = 58 },
|
|
{ key = "lored", text = function() return FW.L.BEAST_STATUS_LORED end, w = 66 },
|
|
{ key = "tamed", text = function() return FW.L.BEAST_STATUS_TAMED end, w = 60 },
|
|
{ key = "unknown", text = function() return FW.L.BEAST_STATUS_UNKNOWN end, w = 60 },
|
|
}
|
|
local prev
|
|
for _, def in ipairs(statusDefs) do local def = def
|
|
local b = UI.CreateButton(f, def.text(), def.w, 22, function()
|
|
filter.status = def.key or nil
|
|
if f.Refresh then f.Refresh() end
|
|
end, "ghost")
|
|
UI.SetFont(b.label, "body", 11)
|
|
if prev then
|
|
b:SetPoint("LEFT", prev, "RIGHT", 3, 0)
|
|
else
|
|
b:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -128)
|
|
end
|
|
b.def = def
|
|
statusButtons[#statusButtons + 1] = b
|
|
prev = b
|
|
end
|
|
|
|
local listScroll = UI.CreateScrollFrame(f)
|
|
listScroll:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -158)
|
|
listScroll:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 62)
|
|
listScroll:SetWidth(LIST_W)
|
|
|
|
local emptyLabel = UI.CreateLabel(listScroll.child, "", { size = 12, color = "textDim", justifyV = "TOP" })
|
|
emptyLabel:SetPoint("TOPLEFT", listScroll.child, "TOPLEFT", 4, -6)
|
|
emptyLabel:SetPoint("TOPRIGHT", listScroll.child, "TOPRIGHT", -4, -6)
|
|
emptyLabel:SetHeight(120)
|
|
emptyLabel:SetWordWrap(true)
|
|
|
|
-- Schalter: Startdaten anzeigen oder selbst erkunden
|
|
local seedToggle = UI.CreateCheckbox(f, L.BEAST_SEED_TOGGLE, function()
|
|
return Beasts:SeedEnabled()
|
|
end, function(on)
|
|
Beasts:SetSeedEnabled(on)
|
|
end)
|
|
seedToggle:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 4)
|
|
UI.AttachTooltip(seedToggle, L.BEAST_SEED_TOGGLE, { L.BEAST_SEED_TIP1, L.BEAST_SEED_TIP2 })
|
|
|
|
-- Auf Octo/1.12 zeichnet die Codex-Karte (dieselbe wie "Auf Karte zeigen" in der Datenbank);
|
|
-- ohne Codex bleibt die alte Beasts-Ebene.
|
|
local Overlay = NS.MapOverlay
|
|
do
|
|
local C = FW.Codex
|
|
local M = C and C.Map
|
|
if M and M.Show then
|
|
local W = { _mode = nil, _single = nil, pts = nil }
|
|
setmetatable(W, { __index = function(t, k)
|
|
if k == "mode" or k == "singleID" then
|
|
if rawget(t, "pts") and M.points == rawget(t, "pts") then
|
|
return rawget(t, k == "mode" and "_mode" or "_single")
|
|
end
|
|
return nil
|
|
end
|
|
end })
|
|
local function Put(ids, label, mode, single)
|
|
local pts = Beasts:MapPoints(ids)
|
|
if M:Show(pts, label) then
|
|
W.pts = M.points
|
|
W._mode, W._single = mode, single
|
|
end
|
|
FW:Fire("BEASTS_MAP_CHANGED")
|
|
end
|
|
function W:ShowSingle(id, name)
|
|
Put({ [id] = true }, name, "single", id)
|
|
end
|
|
function W:ShowMany(ids, count)
|
|
Put(ids, string.format(FW.L.BEAST_MAP_MANY, count), "many", nil)
|
|
end
|
|
function W:Clear()
|
|
if M.points and M.points == rawget(W, "pts") then
|
|
M:Clear()
|
|
end
|
|
W.pts, W._mode, W._single = nil, nil, nil
|
|
FW:Fire("BEASTS_MAP_CHANGED")
|
|
end
|
|
function W:Focus() end
|
|
Overlay = W
|
|
end
|
|
end
|
|
local mapToggle = UI.CreateCheckbox(f, L.BEAST_MAP_FILTERED, function()
|
|
return Overlay and Overlay.mode == "many"
|
|
end, function(on)
|
|
if not Overlay then
|
|
return
|
|
end
|
|
if on then
|
|
f.ShowFilteredOnMap()
|
|
else
|
|
Overlay:Clear()
|
|
end
|
|
end)
|
|
mapToggle:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 32)
|
|
UI.AttachTooltip(mapToggle, L.BEAST_MAP_FILTERED, { L.BEAST_MAP_FILTERED_TIP })
|
|
|
|
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 hint = UI.CreateLabel(f, L.BEAST_SELECT, { size = 12, color = "textDim", justifyV = "TOP" })
|
|
hint:SetPoint("TOPLEFT", f, "TOPLEFT", LIST_W + 22, -4)
|
|
hint:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, -4)
|
|
hint:SetWordWrap(true)
|
|
|
|
-- Bild: 3D-Modell des Tiers (aus der NPC-Nummer), solange es nicht laedt das Familien-Symbol
|
|
local portrait = UI.CreatePanel(detail, "bgDeep", "bronze")
|
|
portrait:SetSize(64, 64)
|
|
portrait:SetPoint("TOPLEFT", detail, "TOPLEFT", 0, 0)
|
|
local portraitIcon = portrait:CreateTexture(nil, "ARTWORK")
|
|
portraitIcon:SetPoint("TOPLEFT", portrait, "TOPLEFT", 6, -6)
|
|
portraitIcon:SetPoint("BOTTOMRIGHT", portrait, "BOTTOMRIGHT", -6, 6)
|
|
portraitIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
|
local model = CreateFrame("PlayerModel", nil, portrait)
|
|
model:SetPoint("TOPLEFT", portrait, "TOPLEFT", 2, -2)
|
|
model:SetPoint("BOTTOMRIGHT", portrait, "BOTTOMRIGHT", -2, 2)
|
|
model:SetAlpha(0)
|
|
-- 1.12 kennt OnModelLoaded nicht: dann bleibt das Modell unsichtbar und das Symbol steht
|
|
pcall(model.SetScript, model, "OnModelLoaded", function(self)
|
|
self:SetAlpha(1)
|
|
portraitIcon:Hide()
|
|
end)
|
|
|
|
local nameLabel = UI.CreateLabel(detail, "", { font = "heading", size = 20, color = "goldLight" })
|
|
nameLabel:SetPoint("TOPLEFT", detail, "TOPLEFT", 76, -2)
|
|
nameLabel:SetWidth(330)
|
|
nameLabel:SetWordWrap(false)
|
|
|
|
local subLabel = UI.CreateLabel(detail, "", { size = 12, color = "textDim" })
|
|
subLabel:SetPoint("TOPLEFT", detail, "TOPLEFT", 76, -32)
|
|
subLabel:SetWidth(400)
|
|
subLabel:SetWordWrap(false)
|
|
|
|
local mapButton = UI.CreateButton(detail, L.BEAST_MAP_SHOW, 170, 22, function()
|
|
local id = Beasts.selectedID
|
|
if not (Overlay and id) then
|
|
return
|
|
end
|
|
if Overlay.mode == "single" and Overlay.singleID == id then
|
|
Overlay:Clear()
|
|
else
|
|
Overlay:ShowSingle(id, Beasts:Summary(id).name)
|
|
Overlay:Focus(selectedGroup)
|
|
end
|
|
end, "primary")
|
|
mapButton:SetPoint("TOPLEFT", detail, "TOPLEFT", 76, -46)
|
|
|
|
local stateChip = UI.CreateChip(detail, "", "success")
|
|
stateChip:SetPoint("TOPRIGHT", detail, "TOPRIGHT", 0, -4)
|
|
local sourceChip = UI.CreateChip(detail, "", "textDim")
|
|
sourceChip:SetPoint("RIGHT", stateChip, "LEFT", -6, 0)
|
|
|
|
local headDivider = UI.CreateDivider(detail)
|
|
headDivider:SetPoint("TOPLEFT", detail, "TOPLEFT", 0, -76)
|
|
headDivider:SetPoint("TOPRIGHT", detail, "TOPRIGHT", 0, -76)
|
|
|
|
-- Familienfaktoren
|
|
local cards = {}
|
|
local defs = {
|
|
{ key = "hp", label = L.PET_HEALTH },
|
|
{ key = "dmg", label = L.PET_DAMAGE },
|
|
{ key = "armor", label = L.PET_ARMOR },
|
|
}
|
|
for i, def in ipairs(defs) do
|
|
local card = UI.CreateStatCard(detail, def.label, CARD_W, CARD_H)
|
|
UI.SetFont(card.value, "heading", 15)
|
|
card:SetPoint("TOPLEFT", detail, "TOPLEFT", (i - 1) * (CARD_W + CARD_GAP), -88)
|
|
cards[def.key] = card
|
|
end
|
|
|
|
local coordsArea = UI.CreateTextArea(detail, 100, 64)
|
|
coordsArea:SetPoint("BOTTOMLEFT", detail, "BOTTOMLEFT", 0, 0)
|
|
coordsArea:SetPoint("BOTTOMRIGHT", detail, "BOTTOMRIGHT", 0, 0)
|
|
coordsArea:SetHeight(64)
|
|
local coordsHint = UI.CreateLabel(detail, L.BEAST_COORDS_HINT, { size = 11, color = "textDim" })
|
|
coordsHint:SetPoint("BOTTOMLEFT", coordsArea, "TOPLEFT", 0, 4)
|
|
coordsHint:SetPoint("BOTTOMRIGHT", coordsArea, "TOPRIGHT", 0, 4)
|
|
coordsHint:SetWordWrap(false)
|
|
|
|
local sectionScroll = UI.CreateScrollFrame(detail)
|
|
sectionScroll:SetPoint("TOPLEFT", detail, "TOPLEFT", 0, -146)
|
|
sectionScroll:SetPoint("BOTTOMRIGHT", detail, "BOTTOMRIGHT", 0, 90)
|
|
local stack = NewStack(sectionScroll)
|
|
|
|
---------------- Inhalt fuellen ----------------
|
|
local function CoordsText(g)
|
|
local lines = { g.name }
|
|
local function add(tag, list)
|
|
local limit = math.min(#list, 40)
|
|
for i = 1, limit do
|
|
local p = list[i]
|
|
local times = (p[3] and p[3] > 1) and string.format(" (x%d)", p[3]) or ""
|
|
lines[#lines + 1] = string.format("[%s] %.1f, %.1f%s", tag, p[1] / 10, p[2] / 10, times)
|
|
end
|
|
if #list > limit then
|
|
lines[#lines + 1] = string.format("[%s] ... +%d", tag, #list - limit)
|
|
end
|
|
end
|
|
add(FW.L.BEAST_TAG_OWN, g.own)
|
|
add(FW.L.BEAST_TAG_IMPORT, g.imp)
|
|
add(FW.L.BEAST_TAG_START, g.seed)
|
|
return table.concat(lines, "\n")
|
|
end
|
|
|
|
local ShowDetail
|
|
|
|
local function FillSections(s)
|
|
local L2 = FW.L
|
|
stack:Reset()
|
|
|
|
-- Nahrung
|
|
stack:Heading(L2.BEAST_FOOD)
|
|
local foods = FoodList(s.diet)
|
|
if #foods == 0 then
|
|
stack:Text(L2.BEAST_FOOD_UNKNOWN, "textDim")
|
|
else
|
|
stack:Chips(foods, "goldAntique")
|
|
end
|
|
stack:Gap(6)
|
|
|
|
-- Fundorte
|
|
stack:Heading(L2.BEAST_LOCATIONS)
|
|
local groups = Beasts:Locations(s)
|
|
if #groups == 0 then
|
|
stack:Text(L2.BEAST_LOCATIONS_NONE, "textDim")
|
|
coordsArea:SetText("")
|
|
else
|
|
local keep
|
|
for _, g in ipairs(groups) do
|
|
if selectedGroup == g.mapID then
|
|
keep = g
|
|
end
|
|
end
|
|
if not keep then
|
|
keep = groups[1]
|
|
selectedGroup = keep.mapID
|
|
end
|
|
for _, g in ipairs(groups) do local g = g
|
|
local tags = {}
|
|
if #g.own > 0 then tags[#tags + 1] = L2.BEAST_TAG_OWN .. " " .. #g.own end
|
|
if #g.imp > 0 then tags[#tags + 1] = L2.BEAST_TAG_IMPORT .. " " .. #g.imp end
|
|
if #g.seed > 0 then tags[#tags + 1] = L2.BEAST_TAG_START .. " " .. #g.seed end
|
|
stack:Row(g.name, table.concat(tags, " | "), "textDim", function()
|
|
selectedGroup = g.mapID
|
|
FillSections(s)
|
|
end, g.mapID == selectedGroup)
|
|
end
|
|
coordsArea:SetText(CoordsText(keep))
|
|
end
|
|
stack:Gap(6)
|
|
|
|
-- Faehigkeiten durch Zaehmen (Startdaten)
|
|
if s.seed and s.seed.t and #s.seed.t > 0 then
|
|
stack:Heading(L2.BEAST_TEACHES)
|
|
for _, spellID in ipairs(s.seed.t) do
|
|
local name, rank = Beasts.SpellInfo(spellID)
|
|
stack:Row(SpellName(spellID), SpellRank(spellID) or "", "goldLight", function()
|
|
if name then
|
|
filter.ability = name
|
|
filter.rank, filter.rankMin = (rank and rank > 0) and rank or nil, false
|
|
if f.Refresh then f.Refresh() end
|
|
end
|
|
end)
|
|
end
|
|
stack:Gap(6)
|
|
end
|
|
|
|
-- Faehigkeiten des Begleiters, beim Zaehmen erfasst
|
|
local pa = (s.own and s.own.petAbilities) or (s.imp and s.imp.petAbilities)
|
|
if pa and #pa > 0 then
|
|
stack:Heading(L2.BEAST_PETABIL)
|
|
for _, a in ipairs(pa) do local a = a
|
|
local right = a.rank and a.rank > 0 and (FW.L.PET_RANK and string.format(FW.L.PET_RANK, a.rank) or ("Rang " .. a.rank)) or ""
|
|
if a.passive then
|
|
right = (right ~= "" and (right .. " | ") or "") .. L2.BEAST_PASSIVE
|
|
end
|
|
stack:Row(a.name, right, "goldLight", function()
|
|
if a.name then
|
|
filter.ability = a.name
|
|
filter.rank, filter.rankMin = (tonumber(a.rank) and tonumber(a.rank) > 0) and tonumber(a.rank) or nil, false
|
|
if f.Refresh then f.Refresh() end
|
|
end
|
|
end)
|
|
end
|
|
stack:Gap(6)
|
|
end
|
|
|
|
-- Hinweise aus Wildtierkunde
|
|
local extra = (s.own and s.own.extra) or (s.imp and s.imp.extra)
|
|
if extra and #extra > 0 then
|
|
stack:Heading(L2.BEAST_EXTRA)
|
|
for _, line in ipairs(extra) do
|
|
stack:Text(line, "text")
|
|
end
|
|
end
|
|
|
|
sectionScroll:SetContentHeight(stack:Height() + 4)
|
|
end
|
|
|
|
function ShowDetail(id)
|
|
local s = id and Beasts:Summary(id)
|
|
if not s then
|
|
detail:Hide()
|
|
hint:Show()
|
|
return
|
|
end
|
|
hint:Hide()
|
|
detail:Show()
|
|
|
|
nameLabel:SetText(s.name)
|
|
subLabel:SetText(Subtitle(s))
|
|
portraitIcon:SetTexture(FamilyIcon(s.fid))
|
|
portraitIcon:Show()
|
|
model:SetAlpha(0)
|
|
pcall(function()
|
|
model:ClearModel()
|
|
model:SetCreature(s.id)
|
|
if model.SetPortraitZoom then
|
|
model:SetPortraitZoom(1)
|
|
end
|
|
end)
|
|
local fileID = model.GetModelFileID and model:GetModelFileID()
|
|
if type(fileID) == "number" and fileID > 0 then
|
|
model:SetAlpha(1)
|
|
portraitIcon:Hide()
|
|
end
|
|
f.UpdateMapButton()
|
|
stateChip:SetText(StatusText(s.status), STATUS_COLOR[s.status])
|
|
if s.own then
|
|
sourceChip:SetText(FW.L.BEAST_TAG_OWN, "textDim")
|
|
sourceChip:Show()
|
|
elseif s.imp then
|
|
sourceChip:SetText(FW.L.BEAST_TAG_IMPORT, "textDim")
|
|
sourceChip:Show()
|
|
elseif s.seed then
|
|
sourceChip:SetText(FW.L.BEAST_TAG_START, "textDim")
|
|
sourceChip:Show()
|
|
else
|
|
sourceChip:Hide()
|
|
end
|
|
|
|
local mods = s.fid and Pet.GetFamilyModsByID(s.fid) or nil
|
|
for key, card in pairs(cards) do
|
|
local v = mods and mods[key]
|
|
if v then
|
|
card:SetValue(string.format("x%.2f", v), FactorColor(v))
|
|
else
|
|
card:SetValue(FW.L.BEAST_FACTOR_UNKNOWN, "textDim")
|
|
end
|
|
end
|
|
|
|
FillSections(s)
|
|
sectionScroll:ScrollToTop()
|
|
end
|
|
|
|
function f.UpdateMapButton()
|
|
local id = Beasts.selectedID
|
|
if not (Overlay and id) then
|
|
return
|
|
end
|
|
if Overlay.mode == "single" and Overlay.singleID == id then
|
|
mapButton:SetLabel(FW.L.BEAST_MAP_HIDE)
|
|
else
|
|
mapButton:SetLabel(FW.L.BEAST_MAP_SHOW)
|
|
end
|
|
end
|
|
|
|
function f.ShowFilteredOnMap()
|
|
local ids, count = {}, 0
|
|
for _, s in ipairs(Beasts:Filtered(filter)) do
|
|
ids[s.id] = true
|
|
count = count + 1
|
|
end
|
|
local wasMany = Overlay.mode == "many"
|
|
Overlay:ShowMany(ids, count)
|
|
if not wasMany then
|
|
Overlay:Focus(nil)
|
|
end
|
|
end
|
|
|
|
local function SelectBeast(id)
|
|
if Beasts.selectedID ~= id then
|
|
selectedGroup = nil
|
|
end
|
|
Beasts.selectedID = id
|
|
for _, row in ipairs(rows) do
|
|
row:SetSelected(row.id == id)
|
|
end
|
|
ShowDetail(id)
|
|
end
|
|
|
|
function f.Refresh()
|
|
local L2 = FW.L
|
|
local list, missing = Beasts:Filtered(filter)
|
|
local total = #Beasts:Index()
|
|
|
|
if filter.ability then
|
|
countLabel:SetText(string.format(L2.BEAST_COUNT_NOABIL, #list, total, missing or 0))
|
|
else
|
|
countLabel:SetText(string.format(L2.BEAST_COUNT, #list, total))
|
|
end
|
|
abilitySelect:SetLabel(filter.ability or L2.BEAST_ALL_ABILITIES)
|
|
local rankText = L2.BEAST_ALL_RANKS
|
|
if filter.rank then
|
|
rankText = string.format(filter.rankMin and L2.BEAST_RANK_MIN or L2.BEAST_RANK_EXACT, filter.rank)
|
|
end
|
|
rankSelect:SetLabel(rankText)
|
|
rankSelect:SetButtonEnabled(filter.ability ~= nil)
|
|
|
|
local famText, zoneText = L2.BEAST_ALL_FAMILIES, L2.BEAST_ALL_ZONES
|
|
if filter.fid then famText = Beasts:FamilyText(filter.fid) end
|
|
if filter.zone then zoneText = filter.zone end
|
|
familySelect:SetLabel(famText)
|
|
zoneSelect:SetLabel(zoneText)
|
|
for _, b in ipairs(statusButtons) do
|
|
local active = (b.def.key or nil) == filter.status
|
|
b:SetStyle(active and "primary" or "ghost")
|
|
end
|
|
seedToggle:Refresh()
|
|
if Beasts:HasSeed() then
|
|
seedToggle:Show()
|
|
else
|
|
seedToggle:Hide()
|
|
end
|
|
|
|
local selectedStillListed = false
|
|
for i, s in ipairs(list) do
|
|
local row = rows[i]
|
|
if not row then
|
|
row = CreateListRow(listScroll.child, SelectBeast)
|
|
rows[i] = row
|
|
end
|
|
row.id = s.id
|
|
row.name:SetText(s.name)
|
|
row.sub:SetText(Subtitle(s))
|
|
row.icon:SetTexture(FamilyIcon(s.fid))
|
|
row.icon:SetDesaturated(s.status == "unknown")
|
|
row.chip:SetText(StatusText(s.status), STATUS_COLOR[s.status])
|
|
row:ClearAllPoints()
|
|
row:SetPoint("TOPLEFT", listScroll.child, "TOPLEFT", 0, -(i - 1) * (ROW_H + ROW_GAP))
|
|
row:SetPoint("TOPRIGHT", listScroll.child, "TOPRIGHT", 0, -(i - 1) * (ROW_H + ROW_GAP))
|
|
row:SetSelected(s.id == Beasts.selectedID)
|
|
row:Show()
|
|
if s.id == Beasts.selectedID then
|
|
selectedStillListed = true
|
|
end
|
|
end
|
|
for i = #list + 1, #rows do
|
|
rows[i]:Hide()
|
|
end
|
|
listScroll:SetContentHeight(math.max(#list * (ROW_H + ROW_GAP), 130))
|
|
|
|
if #list == 0 then
|
|
emptyLabel:SetText((total == 0) and L2.BEAST_EMPTY_EXPLORE or L2.BEAST_EMPTY_FILTER)
|
|
emptyLabel:Show()
|
|
else
|
|
emptyLabel:Hide()
|
|
end
|
|
|
|
if not selectedStillListed then
|
|
Beasts.selectedID = list[1] and list[1].id or nil
|
|
selectedGroup = nil
|
|
for _, row in ipairs(rows) do
|
|
row:SetSelected(row.id == Beasts.selectedID and row:IsShown())
|
|
end
|
|
end
|
|
ShowDetail(Beasts.selectedID)
|
|
if Overlay and Overlay.mode == "many" then
|
|
f.ShowFilteredOnMap()
|
|
end
|
|
mapToggle:Refresh()
|
|
end
|
|
|
|
FW:On("BEASTS_MAP_CHANGED", function()
|
|
mapToggle:Refresh()
|
|
if f.UpdateMapButton then
|
|
f.UpdateMapButton()
|
|
end
|
|
end)
|
|
|
|
f:SetScript("OnHide", ClosePopup)
|
|
|
|
FW:On("BEASTS_UPDATED", function()
|
|
if f:IsVisible() then
|
|
if f.Refresh then f.Refresh() end
|
|
end
|
|
end)
|
|
FW:On("PET_UPDATED", function()
|
|
if f:IsVisible() then
|
|
if f.Refresh then f.Refresh() end
|
|
end
|
|
end)
|
|
|
|
if f.Refresh then f.Refresh() end
|
|
return f
|
|
end
|
|
|
|
UI:RegisterTab("beasts", {
|
|
label = function()
|
|
return FW.L.BEAST_TAB
|
|
end,
|
|
order = 50,
|
|
build = Build,
|
|
onShow = function(f)
|
|
if f.Refresh then f.Refresh() end
|
|
end,
|
|
})
|
|
|
|
SLASH_FREEWOODBEASTS1 = "/fwbeasts"
|
|
SlashCmdList["FREEWOODBEASTS"] = function(msg)
|
|
msg = string.lower(strtrim(msg or ""))
|
|
if msg == "map" or msg == "karte" then
|
|
if NS.MapOverlay then
|
|
NS.MapOverlay:Debug()
|
|
end
|
|
elseif string.sub(msg, 1, 7) == "mapsize" then
|
|
local n = tonumber(string.match(msg, "(%d+)"))
|
|
if n then
|
|
Beasts.db.settings.mapMinSize = math.max(8, math.min(128, n))
|
|
if NS.MapOverlay then
|
|
NS.MapOverlay:Refresh()
|
|
end
|
|
end
|
|
FW:Print(string.format(FW.L.BEAST_MAP_MINSIZE, Beasts.db.settings.mapMinSize or 32))
|
|
elseif msg == "maptest" then
|
|
if NS.MapOverlay then
|
|
NS.MapOverlay:Test()
|
|
end
|
|
else
|
|
UI:Toggle("beasts")
|
|
end
|
|
end
|