模块:Gifting:修订间差异
来自星砂岛百科
更多操作
无编辑摘要 |
无编辑摘要 标签:已被回退 |
||
| 第1行: | 第1行: | ||
local common = require('Module:Common') | local common = require('Module:Common') | ||
local item_common = require('Module:ItemCommon') | |||
local item = require('Module:Item') | |||
local css = require('Module:CSS') | local css = require('Module:CSS') | ||
local p = {} | local p = {} | ||
local | local FIELD_MAP = { | ||
id = 'i', | |||
name = 'n', | |||
name_en = 'en', | |||
type = 't', | |||
type_display = 'td', | |||
item_level = 'lv', | |||
rarity = 'r', | |||
sell_price = 'sp', | |||
base_value = 'bv', | |||
max_stack = 'ms', | |||
max_quality = 'mq', | |||
tags = 'g', | |||
origin = 'o', | |||
locked_origin = 'lo', | |||
use_description = 'ud', | |||
unlock_title = 'ut', | |||
construct_template = 'ct', | |||
construction_template_count = 'ctc', | |||
energy_capacity = 'ec', | |||
production_formula = 'pf', | |||
production_formula_origin = 'pfo', | |||
craft = 'c', | |||
upgrade = 'u', | |||
prev_machine = 'pm', | |||
next_machine = 'nm', | |||
} | } | ||
local | local data_cache | ||
local mapping_cache | |||
local function | local function is_empty(value) | ||
return | if value == nil then | ||
return true | |||
end | |||
for _ in pairs(value) do | |||
return false | |||
end | |||
return true | |||
end | end | ||
local function | local function load_data() | ||
if | if data_cache then | ||
return | return | ||
end | end | ||
if type( | local raw_data | ||
raw_data, mapping_cache = item_common.loadDomainData( | |||
'数据:Machine/machine_index.json', | |||
'数据:Machine/machine_mapping.json' | |||
) | |||
if type(raw_data) == 'table' and type(raw_data.records) == 'table' then | |||
data_cache = raw_data.records | |||
else | |||
data_cache = raw_data or {} | |||
end | end | ||
end | |||
local function find_record(key) | |||
load_data() | |||
return item_common.findRecord(data_cache, mapping_cache, key) | |||
end | end | ||
local function | local function get_short_field(field) | ||
return | return FIELD_MAP[field] or field | ||
end | end | ||
local function | local function get_record_field(record, field) | ||
if | if type(record) ~= 'table' then | ||
return | return nil | ||
end | end | ||
local short_key = get_short_field(field) | |||
if record[short_key] ~= nil then | |||
return record[short_key] | |||
end | end | ||
return record[field] | |||
end | end | ||
local function | local function get_craft_field(craft, short_key, long_key) | ||
if type(craft) ~= 'table' then | |||
return nil | |||
if | end | ||
return | if craft[short_key] ~= nil then | ||
return craft[short_key] | |||
end | end | ||
return | return craft[long_key] | ||
end | end | ||
local function | local function format_time(seconds) | ||
seconds = tonumber(seconds) or 0 | |||
if seconds <= 0 then | |||
if | |||
return '' | return '' | ||
end | end | ||
if seconds < 60 then | |||
return tostring(math.floor(seconds)) .. '秒' | |||
if | |||
return | |||
end | end | ||
local minutes = math.floor(seconds / 60) | |||
local remain = math.floor(seconds % 60) | |||
if remain == 0 then | |||
return tostring(minutes) .. '分' | |||
local | |||
if | |||
return | |||
end | end | ||
return tostring(minutes) .. '分' .. tostring(remain) .. '秒' | |||
end | end | ||
local function | local function render_materials(frame, materials) | ||
if is_empty(materials) then | |||
return '' | |||
end | end | ||
local | local parts = {} | ||
for item_id, count in pairs(materials) do | |||
parts[#parts + 1] = frame:expandTemplate{ | |||
title = 'Item', | |||
args = { item_id, tostring(count), class = 'block' }, | |||
} | |||
end | end | ||
return table.concat(parts, '') | |||
end | |||
local function render_item_template(frame, item_id) | |||
local resolved_id = common.trim(item_id or '') | |||
if resolved_id == '' then | |||
return '' | |||
if | |||
end | end | ||
local css_out = css.quickCall('Item') or '' | |||
return css_out .. item.renderItemWithArgs(frame, { resolved_id }) | |||
return | |||
end | end | ||
local function | local function render_craft_table(title_text, station_label, station_value, materials_label, materials_value, time_label, time_value, exp_label, exp_value) | ||
local | local out = {} | ||
out[#out + 1] = '<table class="wikitable machine-craft-table">' | |||
out[#out + 1] = '<tr><th colspan="2">' .. title_text .. '</th></tr>' | |||
out[#out + 1] = '<tr><th>' .. station_label .. '</th><td>' .. station_value .. '</td></tr>' | |||
out[#out + 1] = '<tr><th>' .. materials_label .. '</th><td>' .. materials_value .. '</td></tr>' | |||
if time_value ~= '' then | |||
out[#out + 1] = '<tr><th>' .. time_label .. '</th><td>' .. time_value .. '</td></tr>' | |||
if | |||
end | end | ||
if exp_value ~= '' then | |||
out[#out + 1] = '<tr><th>' .. exp_label .. '</th><td>' .. exp_value .. '</td></tr>' | |||
end | end | ||
out[#out + 1] = '</table>' | |||
return table.concat(out, '\n') | |||
return | |||
end | end | ||
function p.getField(frame) | |||
local key = common.getArg(frame, 1, '') | |||
local field = common.getArg(frame, 2, '') | |||
if field == '' then | |||
local | return '' | ||
if | |||
end | end | ||
local | local record = find_record(key) | ||
if not record then | |||
return '' | |||
if | |||
end | end | ||
if | local craft = get_record_field(record, 'craft') | ||
local | if field == 'craft_machine' and craft then | ||
if | local machine_id = get_craft_field(craft, 'm', 'machine') | ||
if machine_id and machine_id ~= '' then | |||
return render_item_template(frame, machine_id) | |||
end | end | ||
return '' | |||
end | end | ||
if field == 'craft_time' and craft then | |||
if | return format_time(get_craft_field(craft, 't', 'time')) | ||
end | end | ||
if field == 'craft_exp' and craft then | |||
if | return common.toText(get_craft_field(craft, 'e', 'exp')) | ||
end | end | ||
local upgrade = get_record_field(record, 'upgrade') | |||
if | if field == 'upgrade_from' and upgrade then | ||
local | local from_id = get_craft_field(upgrade, 'f', 'from_machine') | ||
if from_id and from_id ~= '' then | |||
local from_name = item.getNameByKey(from_id) | |||
if from_name and from_name ~= '' then | |||
return '[[' .. from_name .. ']]' | |||
end | |||
end | end | ||
return '' | |||
end | end | ||
if field == 'upgrade_time' and upgrade then | |||
if | return format_time(get_craft_field(upgrade, 't', 'time')) | ||
return | |||
end | end | ||
if field == 'upgrade_exp' and upgrade then | |||
if | return common.toText(get_craft_field(upgrade, 'e', 'exp')) | ||
end | end | ||
if | if field == 'construction_template_count' then | ||
local value = tonumber(get_record_field(record, field)) or 0 | |||
if value <= 0 then | |||
return '' | |||
if | |||
end | end | ||
return tostring(value) | |||
end | end | ||
if field == 'energy_capacity' then | |||
local value = tonumber(get_record_field(record, field)) or 0 | |||
if value <= 0 then | |||
return '' | |||
if | |||
return | |||
end | end | ||
return tostring(value) | |||
end | end | ||
if field == 'prev_machine' then | |||
local prev_id = get_record_field(record, 'prev_machine') | |||
if prev_id and prev_id ~= '' then | |||
return render_item_template(frame, prev_id) | |||
end | end | ||
return '' | |||
end | end | ||
if field == 'next_machine' then | |||
local next_id = get_record_field(record, 'next_machine') | |||
local | if next_id and next_id ~= '' then | ||
if | return render_item_template(frame, next_id) | ||
end | end | ||
return '' | return '' | ||
end | end | ||
return common.toText(get_record_field(record, field)) | |||
end | end | ||
function p.ingredientList(frame) | |||
local key = common.getArg(frame, 1, '') | |||
local record = find_record(key) | |||
if not record then | |||
local | |||
if record | |||
return '' | return '' | ||
end | end | ||
local craft = get_record_field(record, 'craft') | |||
local | if not craft then | ||
if | |||
return '' | return '' | ||
end | end | ||
return render_materials(frame, get_craft_field(craft, 'mat', 'materials')) | |||
end | |||
local | function p.upgradeIngredientList(frame) | ||
local key = common.getArg(frame, 1, '') | |||
local record = find_record(key) | |||
if not record then | |||
return '' | return '' | ||
end | end | ||
local upgrade = get_record_field(record, 'upgrade') | |||
local | if not upgrade then | ||
if | |||
return '' | return '' | ||
end | end | ||
return | return render_materials(frame, get_craft_field(upgrade, 'mat', 'materials')) | ||
end | end | ||
local | function p.craftInfo(frame) | ||
local key = common.getArg(frame, 1, '') | |||
local record = find_record(key) | |||
if not record then | |||
return '' | return '' | ||
end | end | ||
local | local out = {} | ||
local craft = get_record_field(record, 'craft') | |||
local craft_materials = get_craft_field(craft, 'mat', 'materials') | |||
if craft and not is_empty(craft_materials) then | |||
local machine_id = get_craft_field(craft, 'm', 'machine') | |||
local machine_display = '—' | |||
if machine_id and common.trim(machine_id) ~= '' then | |||
local machine_name = item.getNameByKey(machine_id) | |||
if machine_name and machine_name ~= '' then | |||
machine_display = '[[' .. machine_name .. ']]' | |||
end | end | ||
end | end | ||
out[#out + 1] = render_craft_table( | |||
'制造配方', | |||
'制造站', | |||
machine_display, | |||
'材料', | |||
render_materials(frame, craft_materials), | |||
'时间', | |||
format_time(get_craft_field(craft, 't', 'time')), | |||
'经验', | |||
common.toText(get_craft_field(craft, 'e', 'exp')) | |||
) | |||
end | end | ||
local | local upgrade = get_record_field(record, 'upgrade') | ||
local upgrade_materials = get_craft_field(upgrade, 'mat', 'materials') | |||
if upgrade and not is_empty(upgrade_materials) then | |||
local from_id = get_craft_field(upgrade, 'f', 'from_machine') | |||
local from_display = '—' | |||
if from_id and common.trim(from_id) ~= '' then | |||
local | local from_name = item.getNameByKey(from_id) | ||
if from_name and from_name ~= '' then | |||
from_display = '[[' .. from_name .. ']]' | |||
if | |||
local | |||
if | |||
end | end | ||
end | end | ||
out[#out + 1] = render_craft_table( | |||
'升级配方', | |||
'升级自', | |||
from_display, | |||
'材料', | |||
render_materials(frame, upgrade_materials), | |||
'时间', | |||
format_time(get_craft_field(upgrade, 't', 'time')), | |||
'经验', | |||
common.toText(get_craft_field(upgrade, 'e', 'exp')) | |||
) | |||
end | end | ||
return table.concat(out, '\n') | |||
end | end | ||
local | local recipe_cache | ||
local recipe_list | |||
local field_map | |||
local function | local function load_recipes() | ||
if recipe_cache then | |||
if | return | ||
return | |||
end | end | ||
local data = common.loadJsonData('数据:Machine/machine_recipes.json') or {} | |||
local | recipe_list = data.recipes or {} | ||
recipe_cache = data.by_machine or {} | |||
field_map = (data._meta or {}).field_map or { | |||
result = 'r', | |||
result_count = 'rc', | |||
materials = 'm', | |||
time = 't', | |||
machine = 'mc' | |||
} | } | ||
end | end | ||
function p. | function p.recipeList(frame) | ||
local key = common.getArg(frame, 1, '') | local key = common.getArg(frame, 1, '') | ||
local record = find_record(key) | |||
local record | |||
if not record then | if not record then | ||
return '' | return '' | ||
end | end | ||
-- 获取机器ID | |||
local machine_id = get_record_field(record, 'id') | |||
if not machine_id then | |||
if | |||
return '' | return '' | ||
end | end | ||
local | |||
if not | local machine_key = mw.ustring.lower(machine_id) | ||
return '' | |||
load_recipes() | |||
local recipe_ids = recipe_cache[machine_key] | |||
if not recipe_ids then | |||
return '该机器暂无独有配方。' | |||
end | end | ||
-- 检查是否有配方需要显示时间 | |||
local has_time = false | |||
for _, rid in ipairs(recipe_ids) do | |||
local recipe = recipe_list[rid + 1] | |||
local | if recipe and recipe[field_map.time] and recipe[field_map.time] > 0 then | ||
has_time = true | |||
break | |||
local | |||
if | |||
end | end | ||
end | end | ||
local | -- 构建HTML表格 | ||
local out = {} | |||
out[#out + 1] = '<table class="wikitable">' | |||
out[#out + 1] = '<tr><th>产物</th><th>材料</th>' | |||
if has_time then | |||
out[#out + 1] = '<th>时间</th>' | |||
if | |||
end | end | ||
out[#out + 1] = '</tr>' | |||
for _, rid in ipairs(recipe_ids) do | |||
for _, | local recipe = recipe_list[rid + 1] | ||
local | if recipe then | ||
if | out[#out + 1] = '<tr>' | ||
local | local result_count = recipe[field_map.result_count] or 1 | ||
if | if result_count > 1 then | ||
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result], tostring(result_count), class = 'block'}) .. '</td>' | |||
else | |||
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result], class = 'block'}) .. '</td>' | |||
end | |||
-- 渲染材料 | |||
local materials = {} | |||
local mats = recipe[field_map.materials] or {} | |||
for mat_id, count in pairs(mats) do | |||
materials[#materials + 1] = item.renderItemWithArgs(frame, {mat_id, tostring(count), class = 'block'}) | |||
end | |||
out[#out + 1] = '<td>' .. table.concat(materials, '') .. '</td>' | |||
-- 渲染时间 | |||
if has_time then | |||
local time_str = '' | |||
if recipe[field_map.time] and recipe[field_map.time] > 0 then | |||
time_str = format_time(recipe[field_map.time]) | |||
end | end | ||
out[#out + 1] = '<td>' .. time_str .. '</td>' | |||
end | end | ||
out[#out + 1] = '</tr>' | |||
end | end | ||
end | end | ||
return table.concat( | |||
out[#out + 1] = '</table>' | |||
local css_out = css.quickCall('Item') or '' | |||
return css_out .. table.concat(out, '\n') | |||
end | end | ||
local item_recipe_cache | |||
local function load_item_recipes() | |||
if | if item_recipe_cache then | ||
return | return | ||
end | end | ||
load_recipes() | |||
local data = common.loadJsonData('数据:Machine/machine_recipes.json') or {} | |||
item_recipe_cache = data.by_item or {} | |||
end | |||
local | function p.itemRecipes(frame) | ||
if not | local item_key = common.getArg(frame, 1, '') | ||
if item_key == '' then | |||
item_key = common.getCurrentTitleText() | |||
end | |||
-- 获取物品ID | |||
local item_id = item.getIdByKey(item_key) | |||
if not item_id or item_id == '' then | |||
return '' | return '' | ||
end | end | ||
local | local normalized_id = mw.ustring.lower(item_id) | ||
local | |||
load_item_recipes() | |||
if | local item_data = item_recipe_cache[normalized_id] | ||
if not item_data then | |||
return '' | return '' | ||
end | end | ||
local product_ids = item_data.p or {} | |||
local ingredient_ids = item_data.i or {} | |||
-- 计算数组长度(处理有metatable的情况) | |||
local function count_array(arr) | |||
local count = 0 | |||
local | for _ in pairs(arr) do | ||
count = count + 1 | |||
end | end | ||
return count | |||
end | end | ||
local product_count = count_array(product_ids) | |||
local ingredient_count = count_array(ingredient_ids) | |||
local | |||
if product_count == 0 and ingredient_count == 0 then | |||
if | |||
return '' | return '' | ||
end | end | ||
local | local out = {} | ||
-- 作为产物 | |||
if product_count > 0 then | |||
out[#out + 1] = '<h3>制作配方</h3>' | |||
out[#out + 1] = '<table class="wikitable">' | |||
out[#out + 1] = '<tr><th>产物</th><th>机器</th><th>材料</th><th>时间</th></tr>' | |||
for _, rid in ipairs(product_ids) do | |||
local recipe = recipe_list[rid + 1] | |||
if recipe then | |||
out[#out + 1] = '<tr>' | |||
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result], class = 'block'}) .. '</td>' | |||
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.machine], class = 'block'}) .. '</td>' | |||
local materials = {} | |||
for mat_id, count in pairs(recipe[field_map.materials] or {}) do | |||
materials[#materials + 1] = item.renderItemWithArgs(frame, {mat_id, tostring(count), class = 'block'}) | |||
end | end | ||
out[#out + 1] = '<td>' .. table.concat(materials, '') .. '</td>' | |||
local time_str = '' | |||
if recipe[field_map.time] and recipe[field_map.time] > 0 then | |||
time_str = format_time(recipe[field_map.time]) | |||
end | |||
out[#out + 1] = '<td>' .. time_str .. '</td>' | |||
out[#out + 1] = '</tr>' | |||
end | end | ||
end | end | ||
out[#out + 1] = '</table>' | |||
end | end | ||
-- 作为材料 | |||
if ingredient_count > 0 then | |||
if #out > 0 then | |||
out[#out + 1] = '' | |||
end | |||
out[#out + 1] = '<h3>用于制作</h3>' | |||
out[#out + 1] = '<table class="wikitable">' | |||
out[#out + 1] = '<tr><th>产物</th><th>材料</th><th>机器</th></tr>' | |||
for _, rid in ipairs(ingredient_ids) do | |||
local recipe = recipe_list[rid + 1] | |||
if recipe then | |||
out[#out + 1] = '<tr>' | |||
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result], class = 'block'}) .. '</td>' | |||
-- 渲染材料 | |||
local materials = {} | |||
for mat_id, count in pairs(recipe[field_map.materials] or {}) do | |||
materials[#materials + 1] = item.renderItemWithArgs(frame, {mat_id, tostring(count), class = 'block'}) | |||
end | |||
out[#out + 1] = '<td>' .. table.concat(materials, '') .. '</td>' | |||
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.machine], class = 'block'}) .. '</td>' | |||
out[#out + 1] = '</tr>' | |||
end | |||
end | |||
out[#out + 1] = '</table>' | |||
end | end | ||
return table.concat( | local css_out = css.quickCall('Item') or '' | ||
return css_out .. table.concat(out, '\n') | |||
end | end | ||
function p. | function p.machineAsIngredient(frame) | ||
local key = common.getArg(frame, 1, '') | local key = common.getArg(frame, 1, '') | ||
if | local record = find_record(key) | ||
if not record then | |||
return '' | |||
end | end | ||
local | local machine_id = get_record_field(record, 'id') | ||
if not | if not machine_id then | ||
return | return '' | ||
end | end | ||
local | local machine_key = mw.ustring.lower(machine_id) | ||
load_item_recipes() | |||
local item_data = item_recipe_cache[machine_key] | |||
if not item_data or not item_data.i or #item_data.i == 0 then | |||
return '' | |||
end | end | ||
local out = {} | |||
out[#out + 1] = '=== 用于制作 ===' | |||
out[#out + 1] = '<table class="wikitable">' | |||
out[#out + 1] = '<tr><th>产物</th><th>所需数量</th></tr>' | |||
local | for _, rid in ipairs(item_data.i) do | ||
local recipe = recipe_list[rid + 1] | |||
if recipe then | |||
local count = (recipe[field_map.materials] or {})[machine_id] or 0 | |||
if count > 0 then | |||
out[#out + 1] = '<tr>' | |||
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result]}) .. '</td>' | |||
out[#out + 1] = '<td>' .. tostring(count) .. '</td>' | |||
out[#out + 1] = '</tr>' | |||
end | |||
end | |||
end | end | ||
return | out[#out + 1] = '</table>' | ||
local css_out = css.quickCall('Item') or '' | |||
return css_out .. table.concat(out, '\n') | |||
end | end | ||
return p | return p | ||
2026年3月16日 (一) 15:10的版本
概述
Gifting 提供赠礼偏好查询、角色页标签页渲染与物品反查渲染,供 {{GiftsByNPC}}、{{GiftsByItem}} 等模板调用。
用法
{{#invoke:Gifting|renderNpcTabs|晨星}}
{{#invoke:Gifting|renderGiftsByItem|蜂蜜}}
{{#invoke:Gifting|preferenceList|晨星|loved}}
示例
{{#invoke:Gifting|preferenceListByItem|蜂蜜|liked}}
函数
getField:读取角色赠礼记录中的基础字段。preferenceList:按偏好层级返回角色喜欢或讨厌的物品列表。renderNpcTabs:渲染角色页的赠礼标签页。preferenceListByItem:按物品反查对应的角色列表。renderGiftsByItem:渲染物品页赠礼表格。
数据来源
- 数据:Gifting/gift_preferences.json
- 数据:Gifting/gift_preferences_by_item.json
- 数据:Gifting/gifting_mapping.json
- 数据:Gifting/gift_id_registry.json
local common = require('Module:Common')
local item_common = require('Module:ItemCommon')
local item = require('Module:Item')
local css = require('Module:CSS')
local p = {}
local FIELD_MAP = {
id = 'i',
name = 'n',
name_en = 'en',
type = 't',
type_display = 'td',
item_level = 'lv',
rarity = 'r',
sell_price = 'sp',
base_value = 'bv',
max_stack = 'ms',
max_quality = 'mq',
tags = 'g',
origin = 'o',
locked_origin = 'lo',
use_description = 'ud',
unlock_title = 'ut',
construct_template = 'ct',
construction_template_count = 'ctc',
energy_capacity = 'ec',
production_formula = 'pf',
production_formula_origin = 'pfo',
craft = 'c',
upgrade = 'u',
prev_machine = 'pm',
next_machine = 'nm',
}
local data_cache
local mapping_cache
local function is_empty(value)
if value == nil then
return true
end
for _ in pairs(value) do
return false
end
return true
end
local function load_data()
if data_cache then
return
end
local raw_data
raw_data, mapping_cache = item_common.loadDomainData(
'数据:Machine/machine_index.json',
'数据:Machine/machine_mapping.json'
)
if type(raw_data) == 'table' and type(raw_data.records) == 'table' then
data_cache = raw_data.records
else
data_cache = raw_data or {}
end
end
local function find_record(key)
load_data()
return item_common.findRecord(data_cache, mapping_cache, key)
end
local function get_short_field(field)
return FIELD_MAP[field] or field
end
local function get_record_field(record, field)
if type(record) ~= 'table' then
return nil
end
local short_key = get_short_field(field)
if record[short_key] ~= nil then
return record[short_key]
end
return record[field]
end
local function get_craft_field(craft, short_key, long_key)
if type(craft) ~= 'table' then
return nil
end
if craft[short_key] ~= nil then
return craft[short_key]
end
return craft[long_key]
end
local function format_time(seconds)
seconds = tonumber(seconds) or 0
if seconds <= 0 then
return ''
end
if seconds < 60 then
return tostring(math.floor(seconds)) .. '秒'
end
local minutes = math.floor(seconds / 60)
local remain = math.floor(seconds % 60)
if remain == 0 then
return tostring(minutes) .. '分'
end
return tostring(minutes) .. '分' .. tostring(remain) .. '秒'
end
local function render_materials(frame, materials)
if is_empty(materials) then
return ''
end
local parts = {}
for item_id, count in pairs(materials) do
parts[#parts + 1] = frame:expandTemplate{
title = 'Item',
args = { item_id, tostring(count), class = 'block' },
}
end
return table.concat(parts, '')
end
local function render_item_template(frame, item_id)
local resolved_id = common.trim(item_id or '')
if resolved_id == '' then
return ''
end
local css_out = css.quickCall('Item') or ''
return css_out .. item.renderItemWithArgs(frame, { resolved_id })
end
local function render_craft_table(title_text, station_label, station_value, materials_label, materials_value, time_label, time_value, exp_label, exp_value)
local out = {}
out[#out + 1] = '<table class="wikitable machine-craft-table">'
out[#out + 1] = '<tr><th colspan="2">' .. title_text .. '</th></tr>'
out[#out + 1] = '<tr><th>' .. station_label .. '</th><td>' .. station_value .. '</td></tr>'
out[#out + 1] = '<tr><th>' .. materials_label .. '</th><td>' .. materials_value .. '</td></tr>'
if time_value ~= '' then
out[#out + 1] = '<tr><th>' .. time_label .. '</th><td>' .. time_value .. '</td></tr>'
end
if exp_value ~= '' then
out[#out + 1] = '<tr><th>' .. exp_label .. '</th><td>' .. exp_value .. '</td></tr>'
end
out[#out + 1] = '</table>'
return table.concat(out, '\n')
end
function p.getField(frame)
local key = common.getArg(frame, 1, '')
local field = common.getArg(frame, 2, '')
if field == '' then
return ''
end
local record = find_record(key)
if not record then
return ''
end
local craft = get_record_field(record, 'craft')
if field == 'craft_machine' and craft then
local machine_id = get_craft_field(craft, 'm', 'machine')
if machine_id and machine_id ~= '' then
return render_item_template(frame, machine_id)
end
return ''
end
if field == 'craft_time' and craft then
return format_time(get_craft_field(craft, 't', 'time'))
end
if field == 'craft_exp' and craft then
return common.toText(get_craft_field(craft, 'e', 'exp'))
end
local upgrade = get_record_field(record, 'upgrade')
if field == 'upgrade_from' and upgrade then
local from_id = get_craft_field(upgrade, 'f', 'from_machine')
if from_id and from_id ~= '' then
local from_name = item.getNameByKey(from_id)
if from_name and from_name ~= '' then
return '[[' .. from_name .. ']]'
end
end
return ''
end
if field == 'upgrade_time' and upgrade then
return format_time(get_craft_field(upgrade, 't', 'time'))
end
if field == 'upgrade_exp' and upgrade then
return common.toText(get_craft_field(upgrade, 'e', 'exp'))
end
if field == 'construction_template_count' then
local value = tonumber(get_record_field(record, field)) or 0
if value <= 0 then
return ''
end
return tostring(value)
end
if field == 'energy_capacity' then
local value = tonumber(get_record_field(record, field)) or 0
if value <= 0 then
return ''
end
return tostring(value)
end
if field == 'prev_machine' then
local prev_id = get_record_field(record, 'prev_machine')
if prev_id and prev_id ~= '' then
return render_item_template(frame, prev_id)
end
return ''
end
if field == 'next_machine' then
local next_id = get_record_field(record, 'next_machine')
if next_id and next_id ~= '' then
return render_item_template(frame, next_id)
end
return ''
end
return common.toText(get_record_field(record, field))
end
function p.ingredientList(frame)
local key = common.getArg(frame, 1, '')
local record = find_record(key)
if not record then
return ''
end
local craft = get_record_field(record, 'craft')
if not craft then
return ''
end
return render_materials(frame, get_craft_field(craft, 'mat', 'materials'))
end
function p.upgradeIngredientList(frame)
local key = common.getArg(frame, 1, '')
local record = find_record(key)
if not record then
return ''
end
local upgrade = get_record_field(record, 'upgrade')
if not upgrade then
return ''
end
return render_materials(frame, get_craft_field(upgrade, 'mat', 'materials'))
end
function p.craftInfo(frame)
local key = common.getArg(frame, 1, '')
local record = find_record(key)
if not record then
return ''
end
local out = {}
local craft = get_record_field(record, 'craft')
local craft_materials = get_craft_field(craft, 'mat', 'materials')
if craft and not is_empty(craft_materials) then
local machine_id = get_craft_field(craft, 'm', 'machine')
local machine_display = '—'
if machine_id and common.trim(machine_id) ~= '' then
local machine_name = item.getNameByKey(machine_id)
if machine_name and machine_name ~= '' then
machine_display = '[[' .. machine_name .. ']]'
end
end
out[#out + 1] = render_craft_table(
'制造配方',
'制造站',
machine_display,
'材料',
render_materials(frame, craft_materials),
'时间',
format_time(get_craft_field(craft, 't', 'time')),
'经验',
common.toText(get_craft_field(craft, 'e', 'exp'))
)
end
local upgrade = get_record_field(record, 'upgrade')
local upgrade_materials = get_craft_field(upgrade, 'mat', 'materials')
if upgrade and not is_empty(upgrade_materials) then
local from_id = get_craft_field(upgrade, 'f', 'from_machine')
local from_display = '—'
if from_id and common.trim(from_id) ~= '' then
local from_name = item.getNameByKey(from_id)
if from_name and from_name ~= '' then
from_display = '[[' .. from_name .. ']]'
end
end
out[#out + 1] = render_craft_table(
'升级配方',
'升级自',
from_display,
'材料',
render_materials(frame, upgrade_materials),
'时间',
format_time(get_craft_field(upgrade, 't', 'time')),
'经验',
common.toText(get_craft_field(upgrade, 'e', 'exp'))
)
end
return table.concat(out, '\n')
end
local recipe_cache
local recipe_list
local field_map
local function load_recipes()
if recipe_cache then
return
end
local data = common.loadJsonData('数据:Machine/machine_recipes.json') or {}
recipe_list = data.recipes or {}
recipe_cache = data.by_machine or {}
field_map = (data._meta or {}).field_map or {
result = 'r',
result_count = 'rc',
materials = 'm',
time = 't',
machine = 'mc'
}
end
function p.recipeList(frame)
local key = common.getArg(frame, 1, '')
local record = find_record(key)
if not record then
return ''
end
-- 获取机器ID
local machine_id = get_record_field(record, 'id')
if not machine_id then
return ''
end
local machine_key = mw.ustring.lower(machine_id)
load_recipes()
local recipe_ids = recipe_cache[machine_key]
if not recipe_ids then
return '该机器暂无独有配方。'
end
-- 检查是否有配方需要显示时间
local has_time = false
for _, rid in ipairs(recipe_ids) do
local recipe = recipe_list[rid + 1]
if recipe and recipe[field_map.time] and recipe[field_map.time] > 0 then
has_time = true
break
end
end
-- 构建HTML表格
local out = {}
out[#out + 1] = '<table class="wikitable">'
out[#out + 1] = '<tr><th>产物</th><th>材料</th>'
if has_time then
out[#out + 1] = '<th>时间</th>'
end
out[#out + 1] = '</tr>'
for _, rid in ipairs(recipe_ids) do
local recipe = recipe_list[rid + 1]
if recipe then
out[#out + 1] = '<tr>'
local result_count = recipe[field_map.result_count] or 1
if result_count > 1 then
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result], tostring(result_count), class = 'block'}) .. '</td>'
else
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result], class = 'block'}) .. '</td>'
end
-- 渲染材料
local materials = {}
local mats = recipe[field_map.materials] or {}
for mat_id, count in pairs(mats) do
materials[#materials + 1] = item.renderItemWithArgs(frame, {mat_id, tostring(count), class = 'block'})
end
out[#out + 1] = '<td>' .. table.concat(materials, '') .. '</td>'
-- 渲染时间
if has_time then
local time_str = ''
if recipe[field_map.time] and recipe[field_map.time] > 0 then
time_str = format_time(recipe[field_map.time])
end
out[#out + 1] = '<td>' .. time_str .. '</td>'
end
out[#out + 1] = '</tr>'
end
end
out[#out + 1] = '</table>'
local css_out = css.quickCall('Item') or ''
return css_out .. table.concat(out, '\n')
end
local item_recipe_cache
local function load_item_recipes()
if item_recipe_cache then
return
end
load_recipes()
local data = common.loadJsonData('数据:Machine/machine_recipes.json') or {}
item_recipe_cache = data.by_item or {}
end
function p.itemRecipes(frame)
local item_key = common.getArg(frame, 1, '')
if item_key == '' then
item_key = common.getCurrentTitleText()
end
-- 获取物品ID
local item_id = item.getIdByKey(item_key)
if not item_id or item_id == '' then
return ''
end
local normalized_id = mw.ustring.lower(item_id)
load_item_recipes()
local item_data = item_recipe_cache[normalized_id]
if not item_data then
return ''
end
local product_ids = item_data.p or {}
local ingredient_ids = item_data.i or {}
-- 计算数组长度(处理有metatable的情况)
local function count_array(arr)
local count = 0
for _ in pairs(arr) do
count = count + 1
end
return count
end
local product_count = count_array(product_ids)
local ingredient_count = count_array(ingredient_ids)
if product_count == 0 and ingredient_count == 0 then
return ''
end
local out = {}
-- 作为产物
if product_count > 0 then
out[#out + 1] = '<h3>制作配方</h3>'
out[#out + 1] = '<table class="wikitable">'
out[#out + 1] = '<tr><th>产物</th><th>机器</th><th>材料</th><th>时间</th></tr>'
for _, rid in ipairs(product_ids) do
local recipe = recipe_list[rid + 1]
if recipe then
out[#out + 1] = '<tr>'
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result], class = 'block'}) .. '</td>'
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.machine], class = 'block'}) .. '</td>'
local materials = {}
for mat_id, count in pairs(recipe[field_map.materials] or {}) do
materials[#materials + 1] = item.renderItemWithArgs(frame, {mat_id, tostring(count), class = 'block'})
end
out[#out + 1] = '<td>' .. table.concat(materials, '') .. '</td>'
local time_str = ''
if recipe[field_map.time] and recipe[field_map.time] > 0 then
time_str = format_time(recipe[field_map.time])
end
out[#out + 1] = '<td>' .. time_str .. '</td>'
out[#out + 1] = '</tr>'
end
end
out[#out + 1] = '</table>'
end
-- 作为材料
if ingredient_count > 0 then
if #out > 0 then
out[#out + 1] = ''
end
out[#out + 1] = '<h3>用于制作</h3>'
out[#out + 1] = '<table class="wikitable">'
out[#out + 1] = '<tr><th>产物</th><th>材料</th><th>机器</th></tr>'
for _, rid in ipairs(ingredient_ids) do
local recipe = recipe_list[rid + 1]
if recipe then
out[#out + 1] = '<tr>'
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result], class = 'block'}) .. '</td>'
-- 渲染材料
local materials = {}
for mat_id, count in pairs(recipe[field_map.materials] or {}) do
materials[#materials + 1] = item.renderItemWithArgs(frame, {mat_id, tostring(count), class = 'block'})
end
out[#out + 1] = '<td>' .. table.concat(materials, '') .. '</td>'
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.machine], class = 'block'}) .. '</td>'
out[#out + 1] = '</tr>'
end
end
out[#out + 1] = '</table>'
end
local css_out = css.quickCall('Item') or ''
return css_out .. table.concat(out, '\n')
end
function p.machineAsIngredient(frame)
local key = common.getArg(frame, 1, '')
local record = find_record(key)
if not record then
return ''
end
local machine_id = get_record_field(record, 'id')
if not machine_id then
return ''
end
local machine_key = mw.ustring.lower(machine_id)
load_item_recipes()
local item_data = item_recipe_cache[machine_key]
if not item_data or not item_data.i or #item_data.i == 0 then
return ''
end
local out = {}
out[#out + 1] = '=== 用于制作 ==='
out[#out + 1] = '<table class="wikitable">'
out[#out + 1] = '<tr><th>产物</th><th>所需数量</th></tr>'
for _, rid in ipairs(item_data.i) do
local recipe = recipe_list[rid + 1]
if recipe then
local count = (recipe[field_map.materials] or {})[machine_id] or 0
if count > 0 then
out[#out + 1] = '<tr>'
out[#out + 1] = '<td>' .. item.renderItemWithArgs(frame, {recipe[field_map.result]}) .. '</td>'
out[#out + 1] = '<td>' .. tostring(count) .. '</td>'
out[#out + 1] = '</tr>'
end
end
end
out[#out + 1] = '</table>'
local css_out = css.quickCall('Item') or ''
return css_out .. table.concat(out, '\n')
end
return p