Files
Nanami-UI/DarkmoonGuide.lua
2026-03-24 15:56:28 +08:00

363 lines
14 KiB
Lua

--------------------------------------------------------------------------------
-- Nanami-UI: Darkmoon Faire Buff Guide (暗月马戏团 Buff 指引)
-- Automatically shows a guide when talking to Sayge, or via /dmf command
--------------------------------------------------------------------------------
SFrames.DarkmoonGuide = SFrames.DarkmoonGuide or {}
local DG = SFrames.DarkmoonGuide
local GUIDE_WIDTH = 420
local GUIDE_HEIGHT = 520
local _A = SFrames.ActiveTheme
local SAYGE_NAMES = {
["Sayge"] = true,
["塞格"] = true,
["赛格"] = true,
["Сэйдж"] = true,
}
-- Buff data: { buff name, q1 answer, q2 answer, description, optional alt path }
local BUFF_DATA = {
{ buff = "+10% 伤害", q1 = 1, q2 = 1, star = true, tip = "DPS首选" },
{ buff = "+25 全抗性", q1 = 1, q2 = 2, star = false, tip = "PvP/坦克可选", q1_alt = 2, q2_alt = 3 },
{ buff = "+10% 护甲", q1 = 1, q2 = 3, star = false, tip = "坦克可选", q1_alt = 4, q2_alt = 3 },
{ buff = "+10% 精神", q1 = 2, q2 = 1, star = false, tip = "治疗回蓝", q1_alt = 4, q2_alt = 2 },
{ buff = "+10% 智力", q1 = 2, q2 = 2, star = false, tip = "法系/治疗", q1_alt = 4, q2_alt = 1 },
{ buff = "+10% 耐力", q1 = 3, q2 = 1, star = false, tip = "坦克/PvP" },
{ buff = "+10% 力量", q1 = 3, q2 = 2, star = false, tip = "战士/圣骑" },
{ buff = "+10% 敏捷", q1 = 3, q2 = 3, star = false, tip = "盗贼/猎人" },
}
local Q1_LABELS = {
[1] = "第一项: 我会正面迎战",
[2] = "第二项: 我会说服对方",
[3] = "第三项: 我会帮助别人",
[4] = "第四项: 我会独自思考",
}
local Q2_LABELS = {
[1] = "选第一项",
[2] = "选第二项",
[3] = "选第三项",
}
--------------------------------------------------------------------------------
-- Frame creation
--------------------------------------------------------------------------------
local function CreateGuideFrame()
if DG.frame then return DG.frame end
local f = CreateFrame("Frame", "NanamiDarkmoonGuide", UIParent)
f:SetWidth(GUIDE_WIDTH)
f:SetHeight(GUIDE_HEIGHT)
f:SetPoint("CENTER", UIParent, "CENTER", 0, 40)
f:SetFrameStrata("FULLSCREEN_DIALOG")
f:SetFrameLevel(500)
f:SetMovable(true)
f:EnableMouse(true)
f:SetClampedToScreen(true)
f:RegisterForDrag("LeftButton")
f:SetScript("OnDragStart", function() this:StartMoving() end)
f:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
SFrames:CreateRoundBackdrop(f)
local _pbg = _A.panelBg or { 0.06, 0.05, 0.08, 0.96 }
local _pbd = _A.panelBorder or { 0.45, 0.25, 0.55, 1 }
f:SetBackdropColor(_pbg[1], _pbg[2], _pbg[3], _pbg[4])
f:SetBackdropBorderColor(_pbd[1], _pbd[2], _pbd[3], _pbd[4])
table.insert(UISpecialFrames, "NanamiDarkmoonGuide")
if WorldMapFrame then
local origOnHide = WorldMapFrame:GetScript("OnHide")
WorldMapFrame:SetScript("OnHide", function()
if origOnHide then origOnHide() end
if f:IsShown() then f:Hide() end
end)
end
-- Title bar
local titleBar = CreateFrame("Frame", nil, f)
titleBar:SetHeight(32)
titleBar:SetPoint("TOPLEFT", f, "TOPLEFT", 8, -8)
titleBar:SetPoint("TOPRIGHT", f, "TOPRIGHT", -8, -8)
titleBar:SetBackdrop({
bgFile = "Interface\\Buttons\\WHITE8X8",
edgeFile = "Interface\\Buttons\\WHITE8X8",
tile = false, tileSize = 0, edgeSize = 1,
insets = { left = 1, right = 1, top = 1, bottom = 1 }
})
local _hbg = _A.headerBg or { 0.12, 0.08, 0.15, 0.9 }
local _hbd = _A.headerBorder or { 0.5, 0.3, 0.6, 0.6 }
titleBar:SetBackdropColor(_hbg[1], _hbg[2], _hbg[3], _hbg[4])
titleBar:SetBackdropBorderColor(_hbd[1], _hbd[2], _hbd[3], _hbd[4])
local titleIcon = titleBar:CreateTexture(nil, "ARTWORK")
titleIcon:SetTexture("Interface\\Icons\\INV_Misc_Orb_02")
titleIcon:SetWidth(20)
titleIcon:SetHeight(20)
titleIcon:SetPoint("LEFT", titleBar, "LEFT", 8, 0)
local titleText = SFrames:CreateFontString(titleBar, 14, "LEFT")
titleText:SetPoint("LEFT", titleIcon, "RIGHT", 6, 0)
titleText:SetTextColor(_A.title[1], _A.title[2], _A.title[3])
titleText:SetText("暗月马戏团 Buff 指引")
-- Close button
local closeBtn = CreateFrame("Button", nil, f)
closeBtn:SetWidth(20)
closeBtn:SetHeight(20)
closeBtn:SetPoint("TOPRIGHT", f, "TOPRIGHT", -12, -13)
closeBtn:SetBackdrop({
bgFile = "Interface\\Buttons\\WHITE8X8",
edgeFile = "Interface\\Buttons\\WHITE8X8",
tile = false, tileSize = 0, edgeSize = 1,
insets = { left = 1, right = 1, top = 1, bottom = 1 }
})
local _cbg = _A.closeBtnBg or { 0.3, 0.08, 0.08, 0.9 }
local _cbd = _A.closeBtnBorder or { 0.6, 0.2, 0.2, 0.8 }
local _cbgH = _A.closeBtnHoverBg or { 0.5, 0.1, 0.1, 0.95 }
local _cbdH = _A.closeBtnHoverBorder or { 0.8, 0.3, 0.3, 1 }
closeBtn:SetBackdropColor(_cbg[1], _cbg[2], _cbg[3], _cbg[4])
closeBtn:SetBackdropBorderColor(_cbd[1], _cbd[2], _cbd[3], _cbd[4])
local closeIco = SFrames:CreateIcon(closeBtn, "close", 12)
closeIco:SetDrawLayer("OVERLAY")
closeIco:SetPoint("CENTER", closeBtn, "CENTER", 0, 0)
closeIco:SetVertexColor(1, 0.7, 0.7)
closeBtn:SetScript("OnClick", function() f:Hide() end)
closeBtn:SetScript("OnEnter", function()
this:SetBackdropColor(_cbgH[1], _cbgH[2], _cbgH[3], _cbgH[4])
this:SetBackdropBorderColor(_cbdH[1], _cbdH[2], _cbdH[3], _cbdH[4])
end)
closeBtn:SetScript("OnLeave", function()
this:SetBackdropColor(_cbg[1], _cbg[2], _cbg[3], _cbg[4])
this:SetBackdropBorderColor(_cbd[1], _cbd[2], _cbd[3], _cbd[4])
end)
-- NPC info section
local npcSection = CreateFrame("Frame", nil, f)
npcSection:SetHeight(48)
npcSection:SetPoint("TOPLEFT", titleBar, "BOTTOMLEFT", 0, -8)
npcSection:SetPoint("TOPRIGHT", titleBar, "BOTTOMRIGHT", 0, -8)
local npcLine1 = SFrames:CreateFontString(npcSection, 11, "LEFT")
npcLine1:SetPoint("TOPLEFT", npcSection, "TOPLEFT", 4, 0)
npcLine1:SetPoint("TOPRIGHT", npcSection, "TOPRIGHT", -4, 0)
npcLine1:SetTextColor(_A.sectionTitle[1], _A.sectionTitle[2], _A.sectionTitle[3])
npcLine1:SetText("NPC: |cffffffffSayge (塞格)|r - 暗月马戏团占卜师")
local npcLine2 = SFrames:CreateFontString(npcSection, 10, "LEFT")
npcLine2:SetPoint("TOPLEFT", npcLine1, "BOTTOMLEFT", 0, -4)
npcLine2:SetPoint("TOPRIGHT", npcLine1, "BOTTOMRIGHT", 0, -4)
npcLine2:SetTextColor(_A.dimText[1], _A.dimText[2], _A.dimText[3])
npcLine2:SetText("与赛格对话选择不同答案可获得不同2小时Buff (表中 X→Y = 第1题选X, 第2题选Y)")
-- Separator
local sep1 = f:CreateTexture(nil, "ARTWORK")
sep1:SetTexture("Interface\\Buttons\\WHITE8X8")
sep1:SetHeight(1)
sep1:SetPoint("TOPLEFT", npcSection, "BOTTOMLEFT", 0, -4)
sep1:SetPoint("TOPRIGHT", npcSection, "BOTTOMRIGHT", 0, -4)
local _sep = _A.separator or { 0.4, 0.25, 0.5, 0.5 }
sep1:SetVertexColor(_sep[1], _sep[2], _sep[3], _sep[4])
-- Column headers
local headerY = -104
local colBuff = 12
local colOpt1 = 150
local colOpt2 = 260
local colTip = 355
local hBuff = SFrames:CreateFontString(f, 11, "LEFT")
hBuff:SetPoint("TOPLEFT", f, "TOPLEFT", colBuff, headerY)
hBuff:SetTextColor(_A.sectionTitle[1], _A.sectionTitle[2], _A.sectionTitle[3])
hBuff:SetText("Buff效果")
local hOpt1 = SFrames:CreateFontString(f, 11, "LEFT")
hOpt1:SetPoint("TOPLEFT", f, "TOPLEFT", colOpt1, headerY)
hOpt1:SetTextColor(_A.sectionTitle[1], _A.sectionTitle[2], _A.sectionTitle[3])
hOpt1:SetText("选项1")
local hOpt2 = SFrames:CreateFontString(f, 11, "LEFT")
hOpt2:SetPoint("TOPLEFT", f, "TOPLEFT", colOpt2, headerY)
hOpt2:SetTextColor(_A.sectionTitle[1], _A.sectionTitle[2], _A.sectionTitle[3])
hOpt2:SetText("选项2")
local hTip = SFrames:CreateFontString(f, 11, "LEFT")
hTip:SetPoint("TOPLEFT", f, "TOPLEFT", colTip, headerY)
hTip:SetTextColor(_A.sectionTitle[1], _A.sectionTitle[2], _A.sectionTitle[3])
hTip:SetText("备注")
-- Header separator
local sep2 = f:CreateTexture(nil, "ARTWORK")
sep2:SetTexture("Interface\\Buttons\\WHITE8X8")
sep2:SetHeight(1)
sep2:SetPoint("TOPLEFT", f, "TOPLEFT", 10, headerY - 14)
sep2:SetPoint("TOPRIGHT", f, "TOPRIGHT", -10, headerY - 14)
local _sep2c = _A.separator or { 0.35, 0.2, 0.45, 0.4 }
sep2:SetVertexColor(_sep2c[1], _sep2c[2], _sep2c[3], _sep2c[4])
-- Buff rows
local rowStart = headerY - 22
local rowHeight = 24
for i, data in ipairs(BUFF_DATA) do
local y = rowStart - (i - 1) * rowHeight
-- Alternate row background
if math.fmod(i, 2) == 0 then
local rowBg = f:CreateTexture(nil, "BACKGROUND")
rowBg:SetTexture("Interface\\Buttons\\WHITE8X8")
rowBg:SetHeight(rowHeight)
rowBg:SetPoint("TOPLEFT", f, "TOPLEFT", 8, y + 4)
rowBg:SetPoint("TOPRIGHT", f, "TOPRIGHT", -8, y + 4)
local _rbg = _A.sectionBg or { 0.15, 0.1, 0.2, 0.3 }
rowBg:SetVertexColor(_rbg[1], _rbg[2], _rbg[3], 0.3)
end
-- Star marker for recommended
if data.star then
local star = SFrames:CreateFontString(f, 10, "LEFT")
star:SetPoint("TOPLEFT", f, "TOPLEFT", colBuff - 10, y)
local _stc = _A.title or { 1.0, 0.84, 0.0 }
star:SetTextColor(_stc[1], _stc[2], _stc[3])
star:SetText("*")
end
-- Buff name
local buffName = SFrames:CreateFontString(f, 11, "LEFT")
buffName:SetPoint("TOPLEFT", f, "TOPLEFT", colBuff, y)
if data.star then
local _hl = _A.accentLight or { 0.4, 1.0, 0.4 }
buffName:SetTextColor(_hl[1], _hl[2], _hl[3])
else
buffName:SetTextColor(_A.text[1], _A.text[2], _A.text[3])
end
buffName:SetText(data.buff)
-- Option 1 path (q1→q2)
local opt1Text = SFrames:CreateFontString(f, 11, "CENTER")
opt1Text:SetPoint("TOPLEFT", f, "TOPLEFT", colOpt1, y)
local _o1c = _A.title or { 1, 0.82, 0.5 }
opt1Text:SetTextColor(_o1c[1], _o1c[2], _o1c[3])
opt1Text:SetText(data.q1 .. "" .. data.q2)
-- Option 2 path (alt q1→q2) or "/"
local opt2Text = SFrames:CreateFontString(f, 11, "CENTER")
opt2Text:SetPoint("TOPLEFT", f, "TOPLEFT", colOpt2, y)
if data.q1_alt then
local _o2c = _A.accentDark or { 0.7, 0.82, 1.0 }
opt2Text:SetTextColor(_o2c[1], _o2c[2], _o2c[3])
opt2Text:SetText(data.q1_alt .. "" .. data.q2_alt)
else
opt2Text:SetTextColor(_A.dimText[1], _A.dimText[2], _A.dimText[3])
opt2Text:SetText("/")
end
-- Tip
local tipText = SFrames:CreateFontString(f, 10, "LEFT")
tipText:SetPoint("TOPLEFT", f, "TOPLEFT", colTip, y)
tipText:SetTextColor(_A.dimText[1], _A.dimText[2], _A.dimText[3])
tipText:SetText(data.tip)
end
-- Separator before Q1 detail
local sep3 = f:CreateTexture(nil, "ARTWORK")
sep3:SetTexture("Interface\\Buttons\\WHITE8X8")
sep3:SetHeight(1)
local detailY = rowStart - table.getn(BUFF_DATA) * rowHeight - 4
sep3:SetPoint("TOPLEFT", f, "TOPLEFT", 10, detailY)
sep3:SetPoint("TOPRIGHT", f, "TOPRIGHT", -10, detailY)
local _sep3c = _A.separator or { 0.4, 0.25, 0.5, 0.5 }
sep3:SetVertexColor(_sep3c[1], _sep3c[2], _sep3c[3], _sep3c[4])
-- Q1 dialogue detail header
local q1Header = SFrames:CreateFontString(f, 11, "LEFT")
q1Header:SetPoint("TOPLEFT", f, "TOPLEFT", 12, detailY - 10)
q1Header:SetTextColor(_A.sectionTitle[1], _A.sectionTitle[2], _A.sectionTitle[3])
q1Header:SetText("第一题选项对照:")
-- Q1 options
local q1y = detailY - 28
for idx, label in pairs(Q1_LABELS) do
local line = SFrames:CreateFontString(f, 10, "LEFT")
line:SetPoint("TOPLEFT", f, "TOPLEFT", 18, q1y - (idx - 1) * 16)
line:SetTextColor(_A.text[1], _A.text[2], _A.text[3])
line:SetText("|cffffcc66" .. idx .. ".|r " .. label)
end
-- Q2 dialogue detail header
local q2HeaderY = q1y - 4 * 16 - 8
local q2Header = SFrames:CreateFontString(f, 11, "LEFT")
q2Header:SetPoint("TOPLEFT", f, "TOPLEFT", 12, q2HeaderY)
q2Header:SetTextColor(_A.sectionTitle[1], _A.sectionTitle[2], _A.sectionTitle[3])
q2Header:SetText("第二题: 根据上表 \"X → Y\" 中的Y选对应项 (共3项)")
-- Tip at bottom
local tipY = q2HeaderY - 24
local bottomTip = SFrames:CreateFontString(f, 10, "LEFT")
bottomTip:SetPoint("TOPLEFT", f, "TOPLEFT", 12, tipY)
bottomTip:SetPoint("TOPRIGHT", f, "TOPRIGHT", -12, tipY)
local _btc = _A.title or { 1.0, 0.84, 0.0 }
bottomTip:SetTextColor(_btc[1], _btc[2], _btc[3])
bottomTip:SetText("* 推荐: 大部分职业选 +10% 伤害 (第1题选1, 第2题选1)")
local bottomTip2 = SFrames:CreateFontString(f, 10, "LEFT")
bottomTip2:SetPoint("TOPLEFT", bottomTip, "BOTTOMLEFT", 0, -6)
bottomTip2:SetPoint("TOPRIGHT", bottomTip, "BOTTOMRIGHT", 0, -6)
bottomTip2:SetTextColor(_A.dimText[1], _A.dimText[2], _A.dimText[3])
bottomTip2:SetText("输入 /dmf 可随时打开此面板 | 可拖动移动 | ESC关闭")
f:Hide()
DG.frame = f
return f
end
--------------------------------------------------------------------------------
-- Toggle
--------------------------------------------------------------------------------
function DG:Toggle()
local f = CreateGuideFrame()
if f:IsShown() then
f:Hide()
else
f:Show()
end
end
function DG:Show()
local f = CreateGuideFrame()
f:Show()
end
function DG:Hide()
if DG.frame then DG.frame:Hide() end
end
--------------------------------------------------------------------------------
-- Slash command: /dmf
--------------------------------------------------------------------------------
SLASH_DARKMOONGUIDE1 = "/dmf"
SLASH_DARKMOONGUIDE2 = "/darkmoon"
SlashCmdList["DARKMOONGUIDE"] = function()
DG:Toggle()
end
--------------------------------------------------------------------------------
-- Auto-show when talking to Sayge
--------------------------------------------------------------------------------
local detector = CreateFrame("Frame", "NanamiDarkmoonDetector", UIParent)
detector:RegisterEvent("GOSSIP_SHOW")
detector:SetScript("OnEvent", function()
local npcName = UnitName("npc")
if npcName and SAYGE_NAMES[npcName] then
DG:Show()
end
end)
DEFAULT_CHAT_FRAME:AddMessage("SF: Loading DarkmoonGuide.lua...")