Module:Infobox
此模組用於格式化資訊框資料與根據其自動分類的輔助函式。
--- 用於格式化資訊框資料與根據其自動分類的輔助函式。
-- @module infobox
-- @alias p
-- @require Module:User error
-- @require Module:Yesno
-- @author [[en:User:KockaAdmiralac|KockaAdmiralac]]
-- @author [[en:User:Jacky720|Jacky720]]
-- <nowiki>
local p = {}
-- 匯入模組。
local userError = require('Module:User error')
local yesno = require('Module:Yesno')
local data = mw.loadData('Module:Infobox/data')
-- 模組變數。
local title = mw.title.getCurrentTitle()
-- 私有邏輯。
--- 將分類加入指定的字串表(table 形式)。
-- 僅當目前頁面在主名字空間時有效。
-- @function category
-- @param {table} t 要插入分類的字串(table)
-- @param {table} c 要插入的分類
-- @local
-- 將多個分類插入表中。
function category(t, c)
if title.namespace == 0 and title.text ~= '物品' then
table.insert(t, '[[Category:')
table.insert(t, c)
table.insert(t, ']]')
end
end
function multicategory(t, c)
for _, cat in ipairs(c) do
category(t, cat)
end
end
-- 模組公開函式。
--- 格式化地點參數。
-- 本函式的複雜邏輯用於推斷事件發生的地點與應該將頁面歸類在哪些分類中。
-- 經過此函式的地點參數允許用圓點分隔,並會視為多個獨立地點處理。
-- 本函式可解析以下格式的地點:
-- <pre>撲克城堡 → [[撲克城堡]]</pre>
-- <pre>[[撲克城堡]] → [[撲克城堡]]</pre>
-- <pre>撲克城堡 (一樓) → [[撲克城堡#一樓|撲克城堡]] (一樓)</pre>
-- <pre>[[撲克城堡]] (一樓) → [[撲克城堡#一樓|撲克城堡]] (一樓)</pre>
-- <pre>撲克城堡#一樓 → [[撲克城堡#一樓|撲克城堡]] (一樓)</pre>
-- <pre>[[撲克城堡#一樓]] → [[撲克城堡#一樓|撲克城堡]] (一樓)</pre>
-- <pre>[[島嶼圖版 (原版遊戲)]] → [[島嶼圖版 (原版遊戲)]]</pre>
-- 無效地點會被修剪並原樣返回。
-- @function p.location
-- @param {table} frame Scribunto 的 frame 物件
-- @returns {string} 格式化後的地點
function p.location(frame)
local str = {}
local index = 0
local categories = {}
local infotype = frame.args[2]
for _, location in ipairs(mw.text.split(frame.args[1], '*', true)) do
local trimmed = mw.text.trim(location)
if trimmed ~= '' then
index = index + 1
if index == 2 then
table.insert(str, 1, '* ')
end
local link, text = mw.ustring.match(trimmed, '^%[%[([^%]]+)%]%]%s*%(?([^)]*)%)?$')
if link == nil then
link, text = mw.ustring.match(trimmed, '([^%](]+)%s*%(?([^)]*)%)?$')
end
if link then
link = mw.text.trim(link)
if index > 1 then
table.insert(str, '\n* ')
end
local spl = mw.text.split(link, '#', true)
local name = spl[1]
local hash = spl[2]
if text and text ~= '' and not hash then
hash = text
end
local ldata = data.locations[name]
if ldata then
if ldata.link then
link = ldata.link
end
if ldata.categories then
multicategory(categories, ldata.categories)
end
if ldata.condcats and infotype and ldata.condcats[infotype] then
multicategory(categories, ldata.condcats[infotype])
end
if ldata.nolink then
table.insert(str, link)
else
table.insert(str, '[[')
table.insert(str, name)
if hash then
table.insert(str, '#')
table.insert(str, hash)
table.insert(str, '|')
table.insert(str, name)
table.insert(str, ']]')
table.insert(str, ' (')
table.insert(str, hash)
table.insert(str, ')')
else
table.insert(str, ']]')
end
end
else
table.insert(str, trimmed)
end
end
end
end
return table.concat(str) .. table.concat(categories)
end
--- 格式化物品的類型與武器子類型。
-- @function p.itemtype
-- @param {table} frame Scribunto 的 frame 物件
-- @returns {string} 格式化後的物品類型與武器子類型
function p.itemtype(frame)
local str = {}
for _, itemtype in ipairs(mw.text.split(frame.args[1], ',', true)) do
itemtype = mw.text.trim(itemtype)
if data.itemtypes[itemtype] then
if str[1] then
if str[1] ~= '* ' then
table.insert(str, 1, '* ')
end
table.insert(str, '\n* ')
end
table.insert(str, itemtype)
-- 根據裝備參數,分類為劍類武器、斧類武器、圍巾類武器和戒指類武器
if itemtype == '武器' and data.weapontypes[frame.args[2]] then
category(str, data.weapontypes[frame.args[2]])
else
category(str, data.itemtypes[itemtype])
end
end
end
return table.concat(str)
end
--- 格式化遊戲機制類型。
-- @function p.mechanics
-- @param {table} frame Scribunto 的 frame 物件
-- @returns {string} 格式化後的遊戲機制類型
function p.mechanics(frame)
local t = frame.args[1]
if not t or not data.mechanics[t] then
return userError(
'機制類型無效或未指定',
'含有使用者錯誤的頁面'
)
end
local d = data.mechanics[t]
local str = {d}
category(str, table.concat({d}))
return table.concat(str)
end
--- 格式化敵人資訊框中的 ACT 欄位。
-- @function p.act
-- @param {table} frame Scribunto 的 frame 物件
-- @returns {string} 格式化後的 ACT 列表
function p.act(frame)
local str = {}
local index = 0
local nocheck = frame.args[2]
nocheck = mw.text.trim(nocheck)
nocheck = mw.text.split(nocheck, '%s*,%s*')
for _, battle in ipairs(mw.text.split(frame.args[1], '*', true)) do
-- battle:傳入函式的某場戰鬥的 ACT 指令
-- 例如:"Cry (First box encounter)"
-- acts:除了"檢查(Check)"以外的 ACT 指令
-- 例如:"Cry"
-- form:對應該 ACT 的型態或戰鬥情境
-- 例如:"First box encounter"
-- "nocheck" 參數(frame.args[2])可防止自動加入"檢查(Check)"指令
battle = mw.text.trim(battle)
if battle ~= '' then
index = index + 1
if index == 2 then
table.insert(str, 1, '* ')
end
if index > 1 then
table.insert(str, '\n* ')
end
local acts, form = mw.ustring.match(battle, '^([^(]*)%s*%(?([^)]*)%)?$')
if not yesno(nocheck[index] or nocheck[1], false) then
if acts ~= '' then
table.insert(str, '檢查、')
else
table.insert(str, '檢查')
end
end
table.insert(str, acts)
if form ~= '' then
table.insert(str, ' (')
table.insert(str, form)
table.insert(str, ')')
end
end
end
return table.concat(str)
end
--- 若指定了 <code>gold</code> 參數,則附加"敵人"分類。
-- 用以判定該角色是否為敵人。
-- @function p.gold
-- @param {table} Scribunto 的 frame 物件
-- @returns {string} 加入分類後的相同內容
function p.gold(frame)
local str = {frame.args[1]}
category(str, '敵人')
return table.concat(str)
end
--- 用於格式化回到 Undertale Wiki 的連結參數。
-- 僅用於 Deltarune Wiki。
-- @function p.undertale
-- @param {table} frame Scribunto 的 frame 物件
-- @returns {string} 格式化後的回歸角色參數
function p.undertale(frame)
local str = {}
local index = 0
local names = frame.args[1]
if yesno(names, false) then
if frame.args[2] == '' then -- 未指定名稱
names = title.text
else
names = frame.args[2]
end
end
-- 多個名稱
for _, name in ipairs(mw.text.split(names, '、', true)) do
local trimmed = mw.text.trim(name)
index = index + 1
if index > 1 then
table.insert(str, '、')
end
table.insert(str, '[[ut:')
table.insert(str, name)
table.insert(str, '|')
table.insert(str, name)
table.insert(str, ']]')
end
if frame.args[2] == '' then -- Don't include category for NPC pages with separated infoboxes
category(str, '回歸角色')
end
return table.concat(str)
end
--- 若參數未提供則顯示"N/A"。
-- @function p.na
-- @param {table} Scribunto 的 frame 物件
-- @returns {string} 若參數未提供則為 "N/A",否則為原值
function p.na(frame)
local val = mw.text.trim(frame.args[1])
if val == '' then
return 'N/A'
else
return val
end
end
--- 當物品在其條目中有多個資訊框時使用(如變體)。
-- @function p.alternative
-- @param {table} frame Scribunto 的 frame 物件
-- @returns {string} 一個斜線加上備用物品名稱
function p.alternative(frame)
local val = mw.text.trim(frame.args[1])
if val ~= '' then
return table.concat({'/', val})
end
end
--- 根據購買價格自動推算販售價格。
-- 僅用於 Deltarune Wiki。
-- @function p.sell
-- @param {table} frame Scribunto 的 frame 物件
-- @returns {string} 物品的販售價格
function p.sell(frame)
local val = tonumber(frame.args[1])
if val then
return math.ceil(val / 2) .. ' D$'
end
end
--- 將地點頁面歸類至 [[:Category:地點]],並若有以地點名稱命名的分類,也一併加入。
-- @function p.locationcats
-- @param {table} frame Scribunto 的 frame 物件
-- @returns {string} 地點的分類列表
function p.locationcats(frame)
local cats = {}
category(cats, '地點')
if data.locationcats[title.text] then
category(cats, title.text)
end
return table.concat(cats)
end
--- Stores item infobox data in item and item_type buckets.
-- @function p.itemdata
-- @param {table} frame Scribunto frame object
function p.itemdata(frame)
if title.namespace ~= 0 then
return
end
local args = frame:getParent().args
local item = args.title or title.text
bucket("item").put({
name = item,
description = args.flavortext,
effects = args.effects and mw.text.killMarkers(args.effects) or nil,
source = args.source,
buy = args.buy,
id = args.id and tonumber(mw.ustring.match(args.id, '^%d+')) or 999
})
if args.type ~= nil then
for _, itemtype in ipairs(mw.text.split(args.type, ',', true)) do
bucket("item_type").put({item = item, type = mw.text.trim(itemtype)})
end
end
end
--- Generates a table listing of items of a certain type.
-- @function p.itemtable
-- @param {table} frame Scribunto frame object
-- @returns {string} Table with items listed
function p.itemtable(frame)
local itemtype = frame.args[1]
local data = bucket('item_type')
.where('type', itemtype)
.join('item', 'item_type.item', 'item.name')
.select(
'item.page_name',
'item.name',
'item.description',
'item.effects',
'item.source',
'item.buy',
'item.id'
)
.orderBy('item.id')
.run()
local itemtable = mw.html.create('table')
:attr('class', 'wikitable items-table')
:tag('tr')
:tag('th')
:wikitext('物品')
:done()
:tag('th')
:wikitext('檢查')
:done()
:tag('th')
:wikitext('效果')
:done()
:tag('th')
:wikitext('來源')
:done()
:tag('th')
:wikitext('價格(黑暗幣)')
:done()
:done()
for _, item in ipairs(data) do
itemtable:tag('tr')
:tag('td')
:wikitext(table.concat({'[[', item['item.page_name'], '|', item['item.name'], ']]'}))
:done()
:tag('td')
:newline()
:wikitext(item['item.description'] or '')
-- See [[Module:Soundtrack]] for why we need the second newline.
:newline()
:done()
:tag('td')
:newline()
:wikitext(item['item.effects'] or 'N/A')
:newline()
:done()
:tag('td')
:newline()
:wikitext(p.location({args = {item['item.source'] or ''}}))
:newline()
:done()
:tag('td')
:newline()
:wikitext(item['item.buy'] or 'N/A')
:newline()
:done()
:done()
end
return tostring(itemtable:done())
end
return p
-- </nowiki>