打开/关闭菜单
331
1.7K
131
11.8K
星露谷物语扩展百科
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

模块:Templates:修订间差异

来自星露谷物语扩展百科
SummerFleur留言 | 贡献
m无编辑摘要
SummerFleur留言 | 贡献
无编辑摘要
第56行: 第56行:
-- 检查页面是否存在
-- 检查页面是否存在
function p.checkPageExistence(frame)
function p.checkPageExistence(frame)
    local pageName = frame.args[1]
local pageName = frame.args[1]
    if mw.title.new(pageName).exists then
if mw.title.new(pageName).exists then
        return "exists" -- return string.format('[[%s]]', pageName)
return "exists" -- return string.format('[[%s]]', pageName)
    else
else
        return "notexists" -- return pageName
return "notexists" -- return pageName
    end
end
end
end


第67行: 第67行:
function p.getVerP(frame)
function p.getVerP(frame)
local versionMapping = {
local versionMapping = {
    ["1.07a"] = "1.0",
["1.07a"] = "1.0",
    ["1.07"] = "1.0",
["1.07"] = "1.0",
    ["1.06"] = "1.0",
["1.06"] = "1.0",
    ["1.051b"] = "1.0",
["1.051b"] = "1.0",
    ["1.051"] = "1.0",
["1.051"] = "1.0",
    ["1.05"] = "1.0",
["1.05"] = "1.0",
    ["1.04"] = "1.0",
["1.04"] = "1.0",
    ["1.03"] = "1.0",
["1.03"] = "1.0",
    ["1.02"] = "1.0",
["1.02"] = "1.0",
    ["1.01"] = "1.0",
["1.01"] = "1.0",
    ["1.0"] = "1.0",
["1.0"] = "1.0",
}
}
    local version = frame.args[1] or "1.6"
local version = frame.args[1] or "1.6"


    if versionMapping[version] then
if versionMapping[version] then
        return "版本历史/1.0"
return "版本历史/1.0"
    end
end
   
    if version == "1.11" then
if version == "1.11" then
    return "版本历史/1.1"
return "版本历史/1.1"
end
end


    local major, minor = version:match("^(%d+)%.(%d+)")
local major, minor = version:match("^(%d+)%.(%d+)")
    if major and minor then
if major and minor then
        return "版本历史/" .. major .. "." .. minor
return "版本历史/" .. major .. "." .. minor
    end
end


    return "版本历史"
return "版本历史"
end
end


-- 获取主版本号
-- 获取主版本号
function p.getVer(frame)
function p.getVer(frame)
    local version = frame.args[1] or "stable"
local version = frame.args[1] or "stable"
    local versions = {
local versions = {
        stable = "1.6",
stable = "1.6",
        beta = "1.6",
beta = "1.6",
        wegame = "1.5.4"
wegame = "1.5.4"
    }
}
    return versions[version] or version
return versions[version] or version
end
end


-- 移除内链
-- 移除内链
function p.removeLinks(frame)
function p.removeLinks(frame)
    local text = frame.args[1] or ""
local text = frame.args[1] or ""
    text = text:gsub("%[%[([^\]]+)%]%]", "%1")
text = text:gsub("%[%[([^\]]+)%]%]", "%1")
    return text
return text
end
end


第118行: 第118行:
-- SVE Quote 兼容性处理
-- SVE Quote 兼容性处理
function p.quoteSVE(frame)
function p.quoteSVE(frame)
    local quote = frame.args[1] or ""
local quote = frame.args[1] or ""
    quote = quote:match("^%s*(.-)%s*$")
quote = quote:match("^%s*(.-)%s*$")
    quote = quote:gsub('^%s*["]*(.-)["]*%s*$', '%1')
quote = quote:gsub('^%s*["]*(.-)["]*%s*$', '%1')
    quote = quote:gsub('^%s*“*(.-)”*%s*$', '%1')
quote = quote:gsub('^%s*“*(.-)”*%s*$', '%1')
    quote = quote:gsub('^%s*“(.-)”%s*$', '%1')
quote = quote:gsub('^%s*“(.-)”%s*$', '%1')
    quote = quote:gsub('^%s*”(.-)“%s*$', '%1')
quote = quote:gsub('^%s*”(.-)“%s*$', '%1')
    return quote
return quote
end
end


-- 获取首条链接
-- 获取首条链接
function p.getFirstLink(frame)
function p.getFirstLink(frame)
    local source = frame.args.source or ""
local source = frame.args.source or ""
    if source == "" then return "" end
if source == "" then return "" end
    local first_link = source:match("%[%[([^%]]-)]%]")
local first_link = source:match("%[%[([^%]]-)]%]")
    return first_link or ""
return first_link or ""
end
end


-- 鱼塘 header 生成
-- 鱼塘 header 生成
function p.generateHeaders(frame)
function p.generateHeaders(frame)
    local args = frame.args
local args = frame.args
    local count = tonumber(args[1]) or 0
local count = tonumber(args[1]) or 0
    local result = {}
local result = {}


    for i = 1, count do
for i = 1, count do
        table.insert(result, string.format('<th data-sort-type="number">%d</th>', i))
table.insert(result, string.format('<th data-sort-type="number">%d</th>', i))
    end
end


    return table.concat(result)
return table.concat(result)
end
end


-- 鱼塘 row 生成
-- 鱼塘 row 生成
function p.generateRow(frame)
function p.generateRow(frame)
    local args = mw.text.split(frame.args[1], ",")
local args = mw.text.split(frame.args[1], ",")
    local result = {}
local result = {}
    local i = 1
local i = 1
    table.insert(result, string.format('<td data-sort-value="%s">%s</td>', args[i + 1], args[i]))
table.insert(result, string.format('<td data-sort-value="%s">%s</td>', args[i + 1], args[i]))
    i = i + 2
i = i + 2
    while i <= #args - 3 do
while i <= #args - 3 do
        local colspan = tonumber(args[i])
local colspan = tonumber(args[i])
        local content = args[i + 1] or "/"
local content = args[i + 1] or "/"
        table.insert(result, string.format('<td colspan="%d">%s</td>', colspan, content))
table.insert(result, string.format('<td colspan="%d">%s</td>', colspan, content))
        i = i + 2
i = i + 2
    end
end
    table.insert(result, string.format('<td>%s</td>', args[i]))
table.insert(result, string.format('<td>%s</td>', args[i]))
    table.insert(result, string.format('<td>%s</td>', args[i + 1]))
table.insert(result, string.format('<td>%s</td>', args[i + 1]))
    return "<tr>" .. table.concat(result) .. "</tr>"
return "<tr>" .. table.concat(result) .. "</tr>"
end
end


-- 隐藏列按钮生成
-- 隐藏列按钮生成
function p.generateButtons(frame)
function p.generateButtons(frame)
    local n = tonumber(frame.args[1])
local n = tonumber(frame.args[1])
    local result = ""
local result = ""


    for i = 1, n do
for i = 1, n do
        result = result .. '<li class="btn btn-default control-column" role="button" data-column="' .. i .. '">第 ' .. i .. ' 列</li>'
result = result .. '<li class="btn btn-default control-column" role="button" data-column="' .. i .. '">第 ' .. i .. ' 列</li>'
    end
end


    return result
return result
end
end


-- 鱼类一览 分类格式化
-- 鱼类一览 分类格式化
function p.formatCategories(frame)
function p.formatCategories(frame)
    local categories = frame.args.categories or ''
local categories = frame.args.categories or ''
    local result = {}
local result = {}
    for category in mw.text.gsplit(categories, ',') do
for category in mw.text.gsplit(categories, ',') do
        local displayText = category:match("%[%[:分类:[^|]+|(.-)%]%]")
local displayText = category:match("%[%[:分类:[^|]+|(.-)%]%]")
        if displayText then
if displayText then
            table.insert(result, mw.text.trim(displayText))
table.insert(result, mw.text.trim(displayText))
        else
else
            table.insert(result, mw.text.trim(category))
table.insert(result, mw.text.trim(category))
        end
end
    end
end
    return table.concat(result, ", ")
return table.concat(result, ", ")
end
end


-- 鱼类一览 检查地点
-- 鱼类一览 检查地点
function p.checkLocations(frame)
function p.checkLocations(frame)
    local input = frame.args[1] or ""
local input = frame.args[1] or ""
    local keywords = { "突变虫穴", "巫婆沼泽", "农场", "夜市" }
local keywords = { "突变虫穴", "巫婆沼泽", "农场", "夜市" }
    local result = {}
local result = {}
    for _, keyword in ipairs(keywords) do
for _, keyword in ipairs(keywords) do
        if input:find(keyword, 1, true) then
if input:find(keyword, 1, true) then
            table.insert(result, keyword)
table.insert(result, keyword)
        end
end
    end
end
    return table.concat(result, ", ")
return table.concat(result, ", ")
end
end


-- 鱼类一览 检查是否全天
-- 鱼类一览 检查是否全天
function p.checkAllDay(frame)
function p.checkAllDay(frame)
    local input = frame.args[1] or ""
local input = frame.args[1] or ""
    if input:find("全天") then
if input:find("全天") then
        return "全天"
return "全天"
    end
end
if input:find("任意") then
if input:find("任意") then
    return "全天"
return "全天"
else
else
return "非全天"
return "非全天"
    end
end
end
end


第231行: 第231行:
-- 结果:500
-- 结果:500
function p.getStatValue(frame)
function p.getStatValue(frame)
    local text = frame.args[1] or ''   -- 第一个参数是要搜索的文本
local text = frame.args[1] or '' -- 第一个参数是要搜索的文本
    local stat = frame.args[2] or ''   -- 第二个参数是要查找的属性名
local stat = frame.args[2] or '' -- 第二个参数是要查找的属性名
    -- 使用模式匹配,用 stat 变量构建匹配模式
-- 使用模式匹配,用 stat 变量构建匹配模式
    local value = string.match(text, stat..".-(%+(%d+))")
local value = string.match(text, stat..".-(%+(%d+))")
    return value or ''
return value or ''
end
end


第346行: 第346行:
local cacheKey = KEY_PREFIX .. "|" .. "csp" .. "|" .. (item or "") .. "|" .. (baseprice or "") .. "|" .. (quality or "") .. "|" .. (profmult or "") .. "|" .. (toFormatOrNotToFormat or "")
local cacheKey = KEY_PREFIX .. "|" .. "csp" .. "|" .. (item or "") .. "|" .. (baseprice or "") .. "|" .. (quality or "") .. "|" .. (profmult or "") .. "|" .. (toFormatOrNotToFormat or "")
if (cache.get(cacheKey)) then
if (cache.get(cacheKey)) then
    local result = cache.get(cacheKey)
local result = cache.get(cacheKey)
    return result
return result
end
end


第412行: 第412行:
local ulang = string.upper(mw.language.getContentLanguage():getCode())
local ulang = string.upper(mw.language.getContentLanguage():getCode())


    if ulang == "ZH" then -- 保留用作参考
if ulang == "ZH" then -- 保留用作参考
    cache.set(cacheKey, formattedSum .. "金", EXP_TIME)
cache.set(cacheKey, formattedSum .. "金", EXP_TIME)
    return formattedSum .. "金"
return formattedSum .. "金"
else
else
cache.set(cacheKey, formattedSum, EXP_TIME)
cache.set(cacheKey, formattedSum, EXP_TIME)
第423行: 第423行:
-- Tabs
-- Tabs
function p.tabs(frame)
function p.tabs(frame)
    local args = frame:getParent().args
local args = frame:getParent().args
    local align = args.align or 'left'
local align = args.align or 'left'
    local tabsData = {}
local tabsData = {}
    local i = 1
local i = 1
    while true do
while true do
        local title = args['title'.. i]
local title = args['title'.. i]
        local content = args['content'.. i]
local content = args['content'.. i]


        if not title or mw.text.trim(title) == '' then
if not title or mw.text.trim(title) == '' then
            break
break
        end
end


        table.insert(tabsData, { title = title, content = content or '' })
table.insert(tabsData, { title = title, content = content or '' })
        i = i + 1
i = i + 1
    end
end


    if #tabsData == 0 then
if #tabsData == 0 then
        return '<div class="errorbox">错误:未提供任何有效的标签页数据。请使用 "|title1=..." 和 "|content1=..." 格式提供参数。</div>'
return '<div class="errorbox">错误:未提供任何有效的标签页数据。请使用 "|title1=..." 和 "|content1=..." 格式提供参数。</div>'
    end
end


    local root = mw.html.create('div')
local root = mw.html.create('div')
    root:addClass('custom-tabs-container')
root:addClass('custom-tabs-container')


    local tablist = root:tag('div')
local tablist = root:tag('div')
    tablist:addClass('custom-tabs-list'):addClass('justify-content-' .. align):attr('role', 'tablist')
tablist:addClass('custom-tabs-list'):addClass('justify-content-' .. align):attr('role', 'tablist')


    local contentContainer = root:tag('div')
local contentContainer = root:tag('div')
    contentContainer:addClass('custom-tabs-content')
contentContainer:addClass('custom-tabs-content')
-- 空置的 details 标签,用于解决样式问题
-- 空置的 details 标签,用于解决样式问题
local defaultTabPanel = contentContainer:tag('div')
local defaultTabPanel = contentContainer:tag('div')
    defaultTabPanel:wikitext("{{#Widget:Details}}{{#Widget:Summary}}{{#Widget:Summary2}}{{#Widget:Details2}}")
defaultTabPanel:wikitext("{{#Widget:Details}}{{#Widget:Summary}}{{#Widget:Summary2}}{{#Widget:Details2}}")
    for index, data in ipairs(tabsData) do
for index, data in ipairs(tabsData) do
        -- 创建标签链接
-- 创建标签链接
        local tabLink = tablist:tag('a')
local tabLink = tablist:tag('a')
        tabLink:addClass('custom-tabs-tab')
tabLink:addClass('custom-tabs-tab')
            :attr('role', 'tab')
:attr('role', 'tab')
            :wikitext(data.title)
:wikitext(data.title)


        -- 创建内容面板
-- 创建内容面板
        local tabPanel = contentContainer:tag('div')
local tabPanel = contentContainer:tag('div')
        tabPanel:addClass('custom-tabs-panel')
tabPanel:addClass('custom-tabs-panel')
            :attr('role', 'tabpanel')
:attr('role', 'tabpanel')


        -- 如果是第一个标签页,直接在模块中设置其为 active 状态
-- 如果是第一个标签页,直接在模块中设置其为 active 状态
        if index == 1 then
if index == 1 then
            tabLink:addClass('is-active')
tabLink:addClass('is-active')
            tabLink:attr('aria-selected', 'true')
tabLink:attr('aria-selected', 'true')
        end
end


        -- 根据是否为第一个标签页,构建不同的 Widget 调用字符串
-- 根据是否为第一个标签页,构建不同的 Widget 调用字符串
        local detailsContent
local detailsContent
        if index == 1 then
if index == 1 then
            -- 为第一个 details 添加 open=true,使其默认展开
-- 为第一个 details 添加 open=true,使其默认展开
            detailsContent = table.concat({
detailsContent = table.concat({
                '{{#Widget:Details1}}', -- 假设 Widget 支持 open 参数
'{{#Widget:Details1}}', -- 假设 Widget 支持 open 参数
                '{{#Widget:Summary}}',
'{{#Widget:Summary}}',
                '{{#Widget:Summary2}}',
'{{#Widget:Summary2}}',
                data.content,
data.content,
                '{{#Widget:Details2}}'
'{{#Widget:Details2}}'
            })
})
        else
else
            -- 其他标签页保持默认关闭状态
-- 其他标签页保持默认关闭状态
            detailsContent = table.concat({
detailsContent = table.concat({
                '{{#Widget:Details}}',
'{{#Widget:Details}}',
                '{{#Widget:Summary}}',
'{{#Widget:Summary}}',
                '{{#Widget:Summary2}}',
'{{#Widget:Summary2}}',
                data.content,
data.content,
                '{{#Widget:Details2}}'
'{{#Widget:Details2}}'
            })
})
        end
end


        -- 将包含 Widget 调用的字符串添加到面板中
-- 将包含 Widget 调用的字符串添加到面板中
        tabPanel:wikitext(detailsContent)
tabPanel:wikitext(detailsContent)
    end
end
   
    -- 空置的 details 标签,用于解决样式问题
-- 空置的 details 标签,用于解决样式问题
local lastTabPanel = contentContainer:tag('div')
local lastTabPanel = contentContainer:tag('div')
    lastTabPanel:wikitext("{{#Widget:Details}}{{#Widget:Summary}}{{#Widget:Summary2}}{{#Widget:Details2}}")
lastTabPanel:wikitext("{{#Widget:Details}}{{#Widget:Summary}}{{#Widget:Summary2}}{{#Widget:Details2}}")


    -- 预处理整个 HTML 结构,解析其中的 Widget 调用
-- 预处理整个 HTML 结构,解析其中的 Widget 调用
    return frame:preprocess(tostring(root))
return frame:preprocess(tostring(root))
end
end


第512行: 第512行:
-- 效果图标和链接的映射表
-- 效果图标和链接的映射表
local effectData = {
local effectData = {
    -- 基础属性
-- 基础属性
    ["攻击"] = {icon = "Attack Buff.png", link = "攻击", aliases = {"attack"}},
["攻击"] = {icon = "Attack Buff.png", link = "攻击", aliases = {"attack"}},
    ["防御"] = {icon = "Defense Buff.png", link = "防御", aliases = {"defense"}},
["防御"] = {icon = "Defense Buff.png", link = "防御", aliases = {"defense"}},
    ["速度"] = {icon = "Speed Buff.png", link = "速度", aliases = {"speed"}},
["速度"] = {icon = "Speed Buff.png", link = "速度", aliases = {"speed"}},
    ["运气"] = {icon = "Luck Buff.png", link = "运气", aliases = {"幸运", "luck"}},
["运气"] = {icon = "Luck Buff.png", link = "运气", aliases = {"幸运", "luck"}},
   
    -- 技能相关
-- 技能相关
    ["采矿"] = {icon = "Mining Skill Icon.png", link = "采矿", aliases = {"挖矿", "mining", "mine"}},
["采矿"] = {icon = "Mining Skill Icon.png", link = "采矿", aliases = {"挖矿", "mining", "mine"}},
    ["钓鱼"] = {icon = "Fishing Skill Icon.png", link = "钓鱼", aliases = {"fishing", "fish"}},
["钓鱼"] = {icon = "Fishing Skill Icon.png", link = "钓鱼", aliases = {"fishing", "fish"}},
    ["耕种"] = {icon = "Farming Skill Icon.png", link = "耕种", aliases = {"farming", "farm"}},
["耕种"] = {icon = "Farming Skill Icon.png", link = "耕种", aliases = {"farming", "farm"}},
    ["采集"] = {icon = "Foraging Skill Icon.png", link = "采集", aliases = {"觅食", "foraging", "forage"}},
["采集"] = {icon = "Foraging Skill Icon.png", link = "采集", aliases = {"觅食", "foraging", "forage"}},
   
    -- 特殊效果
-- 特殊效果
    ["磁力半径"] = {icon = "Magnetism Buff.png", link = "磁力半径", aliases = {"磁性", "magnetic"}},
["磁力半径"] = {icon = "Magnetism Buff.png", link = "磁力半径", aliases = {"磁性", "magnetic"}},
    ["最大能量"] = {icon = "Max Energy Buff.png", link = "最大能量", aliases = {"能量", "energy", "max energy"}},
["最大能量"] = {icon = "Max Energy Buff.png", link = "最大能量", aliases = {"能量", "energy", "max energy"}},
    ["战士能量"] = {icon = "Combat Skill Icon.png", link = "战士能量", aliases = {"warrior", "warrior energy"}},
["战士能量"] = {icon = "Combat Skill Icon.png", link = "战士能量", aliases = {"warrior", "warrior energy"}},
    ["由巴的祝福"] = {icon = "Yoba's Blessing.png", link = "由巴的祝福", aliases = {"无敌", "yoba's blessing"}},
["由巴的祝福"] = {icon = "Yoba's Blessing.png", link = "由巴的祝福", aliases = {"无敌", "yoba's blessing"}},
    ["肾上腺冲击"] = {icon = "Speed Buff.png", link = "肾上腺冲击", aliases = {"肾上腺", "adrenaline rush"}},
["肾上腺冲击"] = {icon = "Speed Buff.png", link = "肾上腺冲击", aliases = {"肾上腺", "adrenaline rush"}},
   
    -- 负面效果
-- 负面效果
    ["眩晕"] = {icon = "Tipsy.png", link = "眩晕", aliases = {"醉酒", "tipsy"}},
["眩晕"] = {icon = "Tipsy.png", link = "眩晕", aliases = {"醉酒", "tipsy"}},
    ["恶心"] = {icon = "Nauseated.png", link = "恶心", aliases = {"反胃", "nauseated"}},
["恶心"] = {icon = "Nauseated.png", link = "恶心", aliases = {"反胃", "nauseated"}},
    ["烧伤"] = {icon = "Burnt.png", link = "烧伤", aliases = {"灼烧", "burnt"}},
["烧伤"] = {icon = "Burnt.png", link = "烧伤", aliases = {"灼烧", "burnt"}},
    ["黑暗"] = {icon = "Darkness.png", link = "黑暗", aliases = {"视野受限", "darkness"}},
["黑暗"] = {icon = "Darkness.png", link = "黑暗", aliases = {"视野受限", "darkness"}},
    ["冻结"] = {icon = "Frozen.png", link = "冻结", aliases = {"冻结的", "frozen"}},
["冻结"] = {icon = "Frozen.png", link = "冻结", aliases = {"冻结的", "frozen"}},
    ["虚弱"] = {icon = "Weakness.png", link = "虚弱", aliases = {"无力", "weakness"}},
["虚弱"] = {icon = "Weakness.png", link = "虚弱", aliases = {"无力", "weakness"}},
    ["黏滑的"] = {icon = "Slimed.png", link = "黏滑的", aliases = {"史莱姆减速", "slimed"}},
["黏滑的"] = {icon = "Slimed.png", link = "黏滑的", aliases = {"史莱姆减速", "slimed"}},
    ["倒霉的"] = {icon = "Jinxed.png", link = "倒霉的", aliases = {"倒霉", "jinxed"}},
["倒霉的"] = {icon = "Jinxed.png", link = "倒霉的", aliases = {"倒霉", "jinxed"}},
   
    -- 食物效果
-- 食物效果
    ["蒜油"] = {icon = "Oil of Garlic Buff.png", link = "蒜油", aliases = {"garlic", "oil of garlic"}},
["蒜油"] = {icon = "Oil of Garlic Buff.png", link = "蒜油", aliases = {"garlic", "oil of garlic"}},
    ["墨汁意大利饺"] = {icon = "Squid Ink Ravioli Buff.png", link = "墨汁意大利饺", aliases = {"免负面", "ravioli", "squid ink ravioli"}},
["墨汁意大利饺"] = {icon = "Squid Ink Ravioli Buff.png", link = "墨汁意大利饺", aliases = {"免负面", "ravioli", "squid ink ravioli"}},
    ["怪兽香水"] = {icon = "Monster Musk Buff.png", link = "怪兽香水", aliases = {"怪物吸引", "monster musk"}},
["怪兽香水"] = {icon = "Monster Musk Buff.png", link = "怪兽香水", aliases = {"怪物吸引", "monster musk"}},
}
}


第550行: 第550行:
local aliasMap = {}
local aliasMap = {}
for mainName, data in pairs(effectData) do
for mainName, data in pairs(effectData) do
    -- 主名称映射到自身
-- 主名称映射到自身
    aliasMap[string.lower(mainName)] = mainName
aliasMap[string.lower(mainName)] = mainName
   
    -- 别名映射到主名称
-- 别名映射到主名称
    for _, alias in ipairs(data.aliases or {}) do
for _, alias in ipairs(data.aliases or {}) do
        aliasMap[string.lower(alias)] = mainName
aliasMap[string.lower(alias)] = mainName
    end
end
end
end


function p.effectIcon(frame)
function p.effectIcon(frame)
    local args = frame:getParent().args
local args = frame:getParent().args
    local effectName = mw.text.trim(args[1] or "")
local effectName = mw.text.trim(args[1] or "")
    local customIcon = mw.text.trim(args[2] or "")
local customIcon = mw.text.trim(args[2] or "")
   
    if effectName == "" then
if effectName == "" then
        return ""
return ""
    end
end
   
    -- 查找效果数据
-- 查找效果数据
    local normalizedName = string.lower(effectName)
local normalizedName = string.lower(effectName)
    local mainName = aliasMap[normalizedName]
local mainName = aliasMap[normalizedName]
   
    if mainName and effectData[mainName] then
if mainName and effectData[mainName] then
        local data = effectData[mainName]
local data = effectData[mainName]
        return string.format(
return string.format(
            "[[File:%s|24px|link=]] [[效果|%s]]",
"[[File:%s|24px|link=]] [[效果|%s]]",
            data.icon,
data.icon,
            data.link
data.link
        )
)
    else
else
        -- 如果没有找到匹配的效果,使用默认格式
-- 如果没有找到匹配的效果,使用默认格式
        local iconName = customIcon ~= "" and customIcon or effectName
local iconName = customIcon ~= "" and customIcon or effectName
        return string.format(
return string.format(
            "[[File:%s.png|24px|link=]] %s",
"[[File:%s.png|24px|link=]] %s",
            iconName,
iconName,
            effectName
effectName
        )
)
    end
end
end
end


local artisanEdibilityMultiplier = {
local artisanEdibilityMultiplier = {
["wine"] = {1.75, 0.1},
["wine"] = {1.75, 0.1, 3.0, 0},
["juice"] = {2.0, 0.4},
["juice"] = {2.0, 0.4, 2.25, 0},
["jelly"] = {2.0, 0.2},
["jelly"] = {2.0, 0.2, 2.0, 50},
["pickles"] = {1.75, 0.25},
["pickles"] = {1.75, 0.25, 2.0, 50},
["dried"] = {3.0, 0.5}
["dried"] = {3.0, 0.5, 7.5, 25},
["honey"] = {2.0, 0.2, 2.0, 100},
["roe"] = {-1, -1, 0.5, 30},
["aged roe"] = {-1, -1, 1.0, 60},
["smoked"] = {1.5, 0.3, 2.0, 0},
}
}


-- calcFlavoredArtisanEdibility
-- calcFlavoredArtisanEdibility
-- 用于计算 Flavored Artisan 的可食用性。
function p.cfae(frame)
function p.cfae(frame)
local sellprice = tonumber(frame.args["sellprice"])
local sellprice = tonumber(frame.args["sellprice"])
local edibility = tonumber(frame.args["edibility"])
local edibility = tonumber(frame.args["edibility"])
local type = frame.args["type"]
local atype = frame.args["type"]
local data
local data


if not sellprice or not edibility or not type then
if not sellprice or not edibility or not atype then
return "参数缺失"
return "参数缺失"
end
end


if edibility >= 0 then
if edibility >= 0 then
data = edibility * artisanEdibilityMultiplier[type][1]
data = edibility * artisanEdibilityMultiplier[atype][1]
elseif edibility == -300 then
elseif edibility == -300 then
data = sellprice * artisanEdibilityMultiplier[type][2]
data = sellprice * artisanEdibilityMultiplier[atype][2]
elseif edibility < 0 then
elseif edibility < 0 then
data = edibility
data = edibility
第619行: 第624行:
local formattedData = mw.language.getContentLanguage():formatNum(math.floor(data))
local formattedData = mw.language.getContentLanguage():formatNum(math.floor(data))
return formattedData
return formattedData
end
-- calcFlavoredArtisanPrice
-- 不使用 Qualityprice 计算 Flavored Artisan 的售出价格。
function p.cfap(frame)
local baseprice = tonumber(frame.args["sellprice"])
local atype = frame.args["type"]
local data
if not baseprice or not atype then
return "参数缺失"
end
data = math.floor(baseprice * artisanEdibilityMultiplier[atype][3] + artisanEdibilityMultiplier[atype][4])
local formattedData = mw.language.getContentLanguage():formatNum(math.floor(data))
return frame:preprocess("{{Price|" .. formattedData .. "}}")
end
end


return p
return p

2025年9月21日 (日) 12:51的版本

[ 创建 | 刷新 ]文档页面
当前模块文档缺失,需要扩充。
local cache = require "mw.ext.LuaCache"
local KEY_PREFIX = "Module:Templates"
local EXP_TIME = 172800

local utils = require("Module:Utils")

local p = {}

-- 表格行拼接(普通)
function p.row(frame)
	local args = frame:getParent().args
	local cells = {}
	local count = 1
	for i, value in ipairs(args) do
		if value ~= 'row' then
			cells[count] = '<td>' .. value .. '</td>'
			count = count + 1
		end
	end
	return '<tr>' .. table.concat(cells) .. '</tr>'
end

-- 表格行拼接(GiftRow)
function p.itemRow(frame)
	local args = frame:getParent().args
	local cells = {}
	local count = 1
	for i, value in ipairs(args) do
		if value ~= 'row' then
			if count == 1 then
				cells[count] = '<td>{{Name|' .. value .. '}}</td>'
				count = count + 1
				cells[count] = '<td>{{Description|' .. value .. '}}</td>'
			elseif count == 3 then
				mw.log (value)
				cells[count] = '<td>' .. value .. '</td>'
			else
				cells[count] = '<td>' .. value .. '</td>'
			end
			count = count + 1
		end
	end
	return frame:preprocess('<tr>' .. table.concat(cells) .. '</tr>')
end


-- source 格式统一化
-- =p.cleanSource{args={"1"}}
function p.cleanSource(frame)
	local result = utils.getArg(frame)
	result = result:gsub('"nametemplate"', '"nametemplateinline"'):gsub('</span><span ', '</span> • <span '):gsub('<br />', ' • ')
	mw.log(result)
	return result
end

-- 检查页面是否存在
function p.checkPageExistence(frame)
	local pageName = frame.args[1]
	if mw.title.new(pageName).exists then
		return "exists" -- return string.format('[[%s]]', pageName)
	else
		return "notexists" -- return pageName
	end
end

-- 获取上层版本号
function p.getVerP(frame)
	local versionMapping = {
		["1.07a"] = "1.0",
		["1.07"] = "1.0",
		["1.06"] = "1.0",
		["1.051b"] = "1.0",
		["1.051"] = "1.0",
		["1.05"] = "1.0",
		["1.04"] = "1.0",
		["1.03"] = "1.0",
		["1.02"] = "1.0",
		["1.01"] = "1.0",
		["1.0"] = "1.0",
	}
	local version = frame.args[1] or "1.6"

	if versionMapping[version] then
		return "版本历史/1.0"
	end
		
	if version == "1.11" then
		return "版本历史/1.1"
	end

	local major, minor = version:match("^(%d+)%.(%d+)")
	if major and minor then
		return "版本历史/" .. major .. "." .. minor
	end

	return "版本历史"
end

-- 获取主版本号
function p.getVer(frame)
	local version = frame.args[1] or "stable"
	local versions = {
		stable = "1.6",
		beta = "1.6",
		wegame = "1.5.4"
	}
	return versions[version] or version
end

-- 移除内链
function p.removeLinks(frame)
	local text = frame.args[1] or ""
	text = text:gsub("%[%[([^\]]+)%]%]", "%1")
	return text
end


-- SVE Quote 兼容性处理
function p.quoteSVE(frame)
	local quote = frame.args[1] or ""
	quote = quote:match("^%s*(.-)%s*$")
	quote = quote:gsub('^%s*["]*(.-)["]*%s*$', '%1')
	quote = quote:gsub('^%s*“*(.-)”*%s*$', '%1')
	quote = quote:gsub('^%s*“(.-)”%s*$', '%1')
	quote = quote:gsub('^%s*”(.-)“%s*$', '%1')
	return quote
end

-- 获取首条链接
function p.getFirstLink(frame)
	local source = frame.args.source or ""
	if source == "" then return "" end
	local first_link = source:match("%[%[([^%]]-)]%]")
	return first_link or ""
end

-- 鱼塘 header 生成
function p.generateHeaders(frame)
	local args = frame.args
	local count = tonumber(args[1]) or 0
	local result = {}

	for i = 1, count do
		table.insert(result, string.format('<th data-sort-type="number">%d</th>', i))
	end

	return table.concat(result)
end

-- 鱼塘 row 生成
function p.generateRow(frame)
	local args = mw.text.split(frame.args[1], ",")
	local result = {}
	local i = 1
	table.insert(result, string.format('<td data-sort-value="%s">%s</td>', args[i + 1], args[i]))
	i = i + 2
	while i <= #args - 3 do
		local colspan = tonumber(args[i])
		local content = args[i + 1] or "/"
		table.insert(result, string.format('<td colspan="%d">%s</td>', colspan, content))
		i = i + 2
	end
	table.insert(result, string.format('<td>%s</td>', args[i]))
	table.insert(result, string.format('<td>%s</td>', args[i + 1]))
	return "<tr>" .. table.concat(result) .. "</tr>"
end

-- 隐藏列按钮生成
function p.generateButtons(frame)
	local n = tonumber(frame.args[1])
	local result = ""

	for i = 1, n do
		result = result .. '<li class="btn btn-default control-column" role="button" data-column="' .. i .. '">第 ' .. i .. ' 列</li>'
	end

	return result
end

-- 鱼类一览 分类格式化
function p.formatCategories(frame)
	local categories = frame.args.categories or ''
	local result = {}
	for category in mw.text.gsplit(categories, ',') do
		local displayText = category:match("%[%[:分类:[^|]+|(.-)%]%]")
		if displayText then
			table.insert(result, mw.text.trim(displayText))
		else
			table.insert(result, mw.text.trim(category))
		end
	end
	return table.concat(result, ", ")
end

-- 鱼类一览 检查地点
function p.checkLocations(frame)
	local input = frame.args[1] or ""
	local keywords = { "突变虫穴", "巫婆沼泽", "农场", "夜市" }
	local result = {}
	for _, keyword in ipairs(keywords) do
		if input:find(keyword, 1, true) then
			table.insert(result, keyword)
		end
	end
	return table.concat(result, ", ")
end

-- 鱼类一览 检查是否全天
function p.checkAllDay(frame)
	local input = frame.args[1] or ""
	if input:find("全天") then
		return "全天"
	end
	if input:find("任意") then
		return "全天"
	else
		return "非全天"
	end
end

-- ExtractStats
-- 从 {{Name}} 模板文本中提取特定属性的数值
-- 示例1:基础使用
-- {{#invoke:Templates|getStatValue|{{Name|Defense|+5}}{{Name|Immunity|+8}}|Immunity}}
-- 结果:8
-- 示例2:提取其他属性
-- {{#invoke:Templates|getStatValue|{{Name|Defense|+5}}{{Name|Immunity|+8}}|Defense}}
-- 结果:5
-- 示例3:处理多位数值
-- {{#invoke:Templates|getStatValue|{{Name|Immunity|+500}}|Immunity}}
-- 结果:500
function p.getStatValue(frame)
	local text = frame.args[1] or ''	-- 第一个参数是要搜索的文本
	local stat = frame.args[2] or ''	-- 第二个参数是要查找的属性名
	-- 使用模式匹配,用 stat 变量构建匹配模式
	local value = string.match(text, stat..".-(%+(%d+))")
	return value or ''
end

-- Calcedibility
-- 用于计算可食用物品的能量值和生命值。
-- 使用了可食用性进行计算;可以用于输出未格式化的原始数字(用于表格排序的 data-sort-value),也可以输出用于实际显示的数字。
--ceh = calculate edibility (energy/health)
function p.ce(frame)
	local item = string.lower(frame.args.im)
	local edibility = tonumber(frame.args.ed)
	local quality = tonumber(frame.args.q)
	local ulang = string.upper(frame.args.ll)
	local result, formattedresult, temp, length

	if edibility == 0 then return 0 end

	if item == "energy" then
		result = math.floor(math.ceil(edibility*2.5) + edibility*quality)
	else
		result = math.floor(math.floor(math.ceil(edibility*2.5) + edibility*quality)*0.45)
	end

	formattedresult = mw.language.getContentLanguage():formatNum(result)

	return formattedresult
end

-- Tcartprice
-- 用于计算给定物品出现在旅行货车时可能的价格范围。
function p.tprice(frame)
	local price = frame.args["price"]
	local separator = frame.args["separator"]
	local gold = frame.args["gold"]
	local space = string.lower(frame.args["spacearoundseparator"])
	local ulang = string.upper(mw.language.getContentLanguage():getCode())

	local formattedprice = "[[File:Gold.png|18px|link=]]"

	if (string.lower(price) == "furniture") then
		formattedprice = formattedprice .. "250"
		
		if space == "true" then formattedprice = formattedprice .. " " .. separator .. " "
		else formattedprice = formattedprice .. separator
		end

		formattedprice = formattedprice .. tostring(mw.language.getContentLanguage():formatNum(2500))
	else
		local lowprice = tonumber(price) * 3
		local highprice = tonumber(price) * 5
		local fmlowprice = tostring(mw.language.getContentLanguage():formatNum(lowprice))
		local fmhighprice = tostring(mw.language.getContentLanguage():formatNum(highprice))
		
		if (lowprice <= 100) then
			formattedprice = formattedprice .. "100"		
		else
			formattedprice = formattedprice .. fmlowprice
		end
			
		if space == "true" then formattedprice = formattedprice .. " " .. separator .. " "
		else formattedprice = formattedprice .. separator
		end
		
		if (highprice <= 1000) then
			formattedprice = formattedprice .. tostring(mw.language.getContentLanguage():formatNum(1000))
		else
			formattedprice = formattedprice .. fmhighprice
		end
	end
	
	return formattedprice .. gold
end

-- Calcgrangepoints
-- 用于计算在星露谷展览会展览给定物品会获得的分数。
function p.cgp(frame)
	--Template must call Calcsellprice and send result here
	local price = tonumber(frame.args.p)
	--quality must be 0, 1, 2, or 4
	local quality = tonumber(frame.args.q)
	local totalpoints = 0

	totalpoints = quality + 1
			
	if (price >= 20) then totalpoints = totalpoints + 1 end
	if (price >= 90) then totalpoints = totalpoints + 1 end
	if (price >= 200) then totalpoints = totalpoints + 1 end
	if (price >= 300 and quality < 2) then
		totalpoints = totalpoints + 1 end
	if (price >= 400 and quality < 1) then
		totalpoints = totalpoints + 1 end	
	
	return totalpoints
end

-- Calcsellprice
-- 用于计算出售给定物品可获得的收入。
-- 可以用于输出未格式化的原始数字(用于表格排序的 data-sort-value),也可以输出用于实际显示的数字。
-- Assumes baseprice is always an integer
-- Adds the language-appropriate letters/characters for 'gold'
-- csp = calculate sell price
function p.csp(frame)
	local Float32Utils = require "Module:Utils/Float32"

	local item = string.lower(frame.args.im)
	local baseprice = tonumber(frame.args.bp)
	local quality = tonumber(frame.args.q)
	local profmult = tonumber(frame.args.pm)
	local toFormatOrNotToFormat = string.lower(frame.args.fm)
	
	local cacheKey = KEY_PREFIX .. "|" .. "csp" .. "|" .. (item or "") .. "|" .. (baseprice or "") .. "|" .. (quality or "") .. "|" .. (profmult or "") .. "|" .. (toFormatOrNotToFormat or "")
	if (cache.get(cacheKey)) then
		local result = cache.get(cacheKey)
		return result
	end

	if ((baseprice == nil) or (baseprice == 0)) then return 0 end

	local qualitymult, artisanprice

	if (profmult == nil) or (item == "coffee") or (item == "oil") then profmult = 1 end

	if (quality == 1) then qualitymult = 1.25
	elseif (quality == 2) then qualitymult = 1.5
	elseif (quality == 4) then qualitymult = 2
	else qualitymult = 1
	end

	-- Calculate some artisan goods prices from base ingredient price
	-- These are needed for data-sort-values on pages like Flowers, Fruit, Vegetables
	if (string.find(item, "wine") ~= nil) then
		artisanprice = (baseprice * 3)
	elseif (string.find(item, "juice") ~= nil) then
		artisanprice = math.floor(baseprice * 2.25)
	elseif ((string.find(item, "jelly")) or (string.find(item, "pickles")) ~= nil) then
		artisanprice = (50 + (baseprice * 2))
	elseif (string.find(item, "dried") ~= nil) then
		artisanprice = math.floor((baseprice * 7.5) + 25)
	elseif (item == "honey") then
		-- This is a hack that works only because
		-- no flower has a base sell price of 100
		if (baseprice ~= 100) then
			artisanprice = (100 + (baseprice * 2))
		else 
			artisanprice = 100
		end
	elseif (string.find(item, "aged roe") ~= nil) then
		artisanprice = (2 * (30 + math.floor(baseprice / 2)))
	elseif (string.find(item, "roe") ~= nil) then
		artisanprice = (30 + math.floor(baseprice / 2))
	elseif (string.find(item, "smoked") ~= nil) then
		artisanprice = (baseprice * 2)
	--[[elseif (item == "pale ale") then artisanprice = 300
	elseif ((item == "beer") or (item == "mead")) then artisanprice = 200
	elseif (item == "green tea") then artisanprice = 100
	elseif (item == "caviar") then artisanprice = 500
	elseif (item == "cheese") then artisanprice = 230
	elseif (item == "goat cheese") then artisanprice = 400
	elseif (item == "cloth") then artisanprice = 470
	elseif (item == "mayonnaise") then artisanprice = 190
	elseif (item == "duck mayonnaise") then artisanprice = 375
	elseif (item == "void mayonnaise") then artisanprice = 275
	elseif (item == "dinosaur mayonnaise") then artisanprice = 800
	elseif (item == "truffle oil") then artisanprice = 1065
	]]
	else artisanprice = baseprice
	end

	local sum = math.floor(Float32Utils.MulFloat32(math.floor(qualitymult * artisanprice),profmult))

	if toFormatOrNotToFormat == "false" then
		cache.set(cacheKey, sum, EXP_TIME)
		return sum
	end

	local formattedSum = mw.language.getContentLanguage():formatNum(sum)
	local ulang = string.upper(mw.language.getContentLanguage():getCode())

	if ulang == "ZH" then -- 保留用作参考
		cache.set(cacheKey, formattedSum .. "金", EXP_TIME)
		return formattedSum .. "金"
	else
		cache.set(cacheKey, formattedSum, EXP_TIME)
		return formattedSum
	end
end

-- Tabs
function p.tabs(frame)
	local args = frame:getParent().args
	local align = args.align or 'left'
	local tabsData = {}
	local i = 1
	while true do
		local title = args['title'.. i]
		local content = args['content'.. i]

		if not title or mw.text.trim(title) == '' then
			break
		end

		table.insert(tabsData, { title = title, content = content or '' })
		i = i + 1
	end

	if #tabsData == 0 then
		return '<div class="errorbox">错误:未提供任何有效的标签页数据。请使用 "|title1=..." 和 "|content1=..." 格式提供参数。</div>'
	end

	local root = mw.html.create('div')
	root:addClass('custom-tabs-container')

	local tablist = root:tag('div')
	tablist:addClass('custom-tabs-list'):addClass('justify-content-' .. align):attr('role', 'tablist')

	local contentContainer = root:tag('div')
	contentContainer:addClass('custom-tabs-content')
	
	-- 空置的 details 标签,用于解决样式问题
	local defaultTabPanel = contentContainer:tag('div')
	defaultTabPanel:wikitext("{{#Widget:Details}}{{#Widget:Summary}}{{#Widget:Summary2}}{{#Widget:Details2}}")
	
	for index, data in ipairs(tabsData) do
		-- 创建标签链接
		local tabLink = tablist:tag('a')
		tabLink:addClass('custom-tabs-tab')
			:attr('role', 'tab')
			:wikitext(data.title)

		-- 创建内容面板
		local tabPanel = contentContainer:tag('div')
		tabPanel:addClass('custom-tabs-panel')
			:attr('role', 'tabpanel')

		-- 如果是第一个标签页,直接在模块中设置其为 active 状态
		if index == 1 then
			tabLink:addClass('is-active')
			tabLink:attr('aria-selected', 'true')
		end

		-- 根据是否为第一个标签页,构建不同的 Widget 调用字符串
		local detailsContent
		if index == 1 then
			-- 为第一个 details 添加 open=true,使其默认展开
			detailsContent = table.concat({
				'{{#Widget:Details1}}', -- 假设 Widget 支持 open 参数
				'{{#Widget:Summary}}',
				'{{#Widget:Summary2}}',
				data.content,
				'{{#Widget:Details2}}'
			})
		else
			-- 其他标签页保持默认关闭状态
			detailsContent = table.concat({
				'{{#Widget:Details}}',
				'{{#Widget:Summary}}',
				'{{#Widget:Summary2}}',
				data.content,
				'{{#Widget:Details2}}'
			})
		end

		-- 将包含 Widget 调用的字符串添加到面板中
		tabPanel:wikitext(detailsContent)
	end
		
	-- 空置的 details 标签,用于解决样式问题
	local lastTabPanel = contentContainer:tag('div')
	lastTabPanel:wikitext("{{#Widget:Details}}{{#Widget:Summary}}{{#Widget:Summary2}}{{#Widget:Details2}}")

	-- 预处理整个 HTML 结构,解析其中的 Widget 调用
	return frame:preprocess(tostring(root))
end

-- Buffs

-- 效果图标和链接的映射表
local effectData = {
	-- 基础属性
	["攻击"] = {icon = "Attack Buff.png", link = "攻击", aliases = {"attack"}},
	["防御"] = {icon = "Defense Buff.png", link = "防御", aliases = {"defense"}},
	["速度"] = {icon = "Speed Buff.png", link = "速度", aliases = {"speed"}},
	["运气"] = {icon = "Luck Buff.png", link = "运气", aliases = {"幸运", "luck"}},
		
	-- 技能相关
	["采矿"] = {icon = "Mining Skill Icon.png", link = "采矿", aliases = {"挖矿", "mining", "mine"}},
	["钓鱼"] = {icon = "Fishing Skill Icon.png", link = "钓鱼", aliases = {"fishing", "fish"}},
	["耕种"] = {icon = "Farming Skill Icon.png", link = "耕种", aliases = {"farming", "farm"}},
	["采集"] = {icon = "Foraging Skill Icon.png", link = "采集", aliases = {"觅食", "foraging", "forage"}},
		
	-- 特殊效果
	["磁力半径"] = {icon = "Magnetism Buff.png", link = "磁力半径", aliases = {"磁性", "magnetic"}},
	["最大能量"] = {icon = "Max Energy Buff.png", link = "最大能量", aliases = {"能量", "energy", "max energy"}},
	["战士能量"] = {icon = "Combat Skill Icon.png", link = "战士能量", aliases = {"warrior", "warrior energy"}},
	["由巴的祝福"] = {icon = "Yoba's Blessing.png", link = "由巴的祝福", aliases = {"无敌", "yoba's blessing"}},
	["肾上腺冲击"] = {icon = "Speed Buff.png", link = "肾上腺冲击", aliases = {"肾上腺", "adrenaline rush"}},
		
	-- 负面效果
	["眩晕"] = {icon = "Tipsy.png", link = "眩晕", aliases = {"醉酒", "tipsy"}},
	["恶心"] = {icon = "Nauseated.png", link = "恶心", aliases = {"反胃", "nauseated"}},
	["烧伤"] = {icon = "Burnt.png", link = "烧伤", aliases = {"灼烧", "burnt"}},
	["黑暗"] = {icon = "Darkness.png", link = "黑暗", aliases = {"视野受限", "darkness"}},
	["冻结"] = {icon = "Frozen.png", link = "冻结", aliases = {"冻结的", "frozen"}},
	["虚弱"] = {icon = "Weakness.png", link = "虚弱", aliases = {"无力", "weakness"}},
	["黏滑的"] = {icon = "Slimed.png", link = "黏滑的", aliases = {"史莱姆减速", "slimed"}},
	["倒霉的"] = {icon = "Jinxed.png", link = "倒霉的", aliases = {"倒霉", "jinxed"}},
		
	-- 食物效果
	["蒜油"] = {icon = "Oil of Garlic Buff.png", link = "蒜油", aliases = {"garlic", "oil of garlic"}},
	["墨汁意大利饺"] = {icon = "Squid Ink Ravioli Buff.png", link = "墨汁意大利饺", aliases = {"免负面", "ravioli", "squid ink ravioli"}},
	["怪兽香水"] = {icon = "Monster Musk Buff.png", link = "怪兽香水", aliases = {"怪物吸引", "monster musk"}},
}

-- 创建别名到主名称的映射
local aliasMap = {}
for mainName, data in pairs(effectData) do
	-- 主名称映射到自身
	aliasMap[string.lower(mainName)] = mainName
		
	-- 别名映射到主名称
	for _, alias in ipairs(data.aliases or {}) do
		aliasMap[string.lower(alias)] = mainName
	end
end

function p.effectIcon(frame)
	local args = frame:getParent().args
	local effectName = mw.text.trim(args[1] or "")
	local customIcon = mw.text.trim(args[2] or "")
		
	if effectName == "" then
		return ""
	end
		
	-- 查找效果数据
	local normalizedName = string.lower(effectName)
	local mainName = aliasMap[normalizedName]
		
	if mainName and effectData[mainName] then
		local data = effectData[mainName]
		return string.format(
			"[[File:%s|24px|link=]] [[效果|%s]]",
			data.icon,
			data.link
		)
	else
		-- 如果没有找到匹配的效果,使用默认格式
		local iconName = customIcon ~= "" and customIcon or effectName
		return string.format(
			"[[File:%s.png|24px|link=]] %s",
			iconName,
			effectName
		)
	end
end

local artisanEdibilityMultiplier = {
	["wine"] = {1.75, 0.1, 3.0, 0},
	["juice"] = {2.0, 0.4, 2.25, 0},
	["jelly"] = {2.0, 0.2, 2.0, 50},
	["pickles"] = {1.75, 0.25, 2.0, 50},
	["dried"] = {3.0, 0.5, 7.5, 25},
	["honey"] = {2.0, 0.2, 2.0, 100},
	["roe"] = {-1, -1, 0.5, 30},
	["aged roe"] = {-1, -1, 1.0, 60},
	["smoked"] = {1.5, 0.3, 2.0, 0},
}

-- calcFlavoredArtisanEdibility
-- 用于计算 Flavored Artisan 的可食用性。
function p.cfae(frame)
	local sellprice = tonumber(frame.args["sellprice"])
	local edibility = tonumber(frame.args["edibility"])
	local atype = frame.args["type"]
	local data

	if not sellprice or not edibility or not atype then
		return "参数缺失"
	end

	if edibility >= 0 then
		data = edibility * artisanEdibilityMultiplier[atype][1]
	elseif edibility == -300 then
		data = sellprice * artisanEdibilityMultiplier[atype][2]
	elseif edibility < 0 then
		data = edibility
	end

	local formattedData = mw.language.getContentLanguage():formatNum(math.floor(data))
	return formattedData
end

-- calcFlavoredArtisanPrice
-- 不使用 Qualityprice 计算 Flavored Artisan 的售出价格。
function p.cfap(frame)
	local baseprice = tonumber(frame.args["sellprice"])
	local atype = frame.args["type"]
	local data

	if not baseprice or not atype then
		return "参数缺失"
	end

	data = math.floor(baseprice * artisanEdibilityMultiplier[atype][3] + artisanEdibilityMultiplier[atype][4])
	local formattedData = mw.language.getContentLanguage():formatNum(math.floor(data))
	return frame:preprocess("{{Price|" .. formattedData .. "}}")
end

return p