模块:Gifting:修订间差异
来自星砂岛百科
更多操作
创建页面 |
无编辑摘要 |
||
| 第372行: | 第372行: | ||
local function item_label_from_index(item_index) | local function item_label_from_index(item_index) | ||
load_item_data() | |||
local item_id = item_id_from_index(item_index) | local item_id = item_id_from_index(item_index) | ||
if item_id == '' then | if item_id == '' then | ||
| 第380行: | 第381行: | ||
local function character_label_from_index(character_index) | local function character_label_from_index(character_index) | ||
load_character_data() | |||
local character_id = character_id_from_index(character_index) | local character_id = character_id_from_index(character_index) | ||
if character_id == '' then | if character_id == '' then | ||
2026年3月9日 (一) 14:36的版本
概述
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 p = {}
local character_cache
local character_records
local character_ids
local character_mapping
local global_rules
local tag_items
local item_cache
local item_by_index
local item_mapping
local item_redirects
local id_registry
local registry_character_ids
local registry_item_ids
local level_to_bucket = {
resonance = 'resonance',
special = 'special',
loved = 'loved',
liked = 'liked',
neutral = 'neutral',
disliked = 'disliked',
hated = 'hated',
r = 'resonance',
s = 'special',
v = 'loved',
k = 'liked',
n = 'neutral',
d = 'disliked',
h = 'hated',
}
local bucket_to_short = {
resonance = 'r',
special = 's',
loved = 'v',
liked = 'k',
neutral = 'n',
disliked = 'd',
hated = 'h',
}
local function normalize_key(value)
return common.normalizeKey(value)
end
local function resolve_level_bucket(level)
if level == nil then
return nil
end
if type(level) == 'string' then
local normalized = normalize_key(level)
return level_to_bucket[normalized]
end
local numeric = tonumber(level)
if numeric == 4 then
return 'resonance'
end
if numeric == 3 then
return 'special'
end
if numeric == 2 then
return 'loved'
end
if numeric == 1 then
return 'liked'
end
if numeric == 0 then
return 'neutral'
end
if numeric == -1 then
return 'disliked'
end
if numeric == -2 then
return 'hated'
end
return nil
end
local function empty_summary()
return {
resonance = { personal = {}, global = {} },
special = { personal = {}, global = {} },
loved = { personal = {}, global = {} },
liked = { personal = {}, global = {} },
neutral = { personal = {}, global = {} },
disliked = { personal = {}, global = {} },
hated = { personal = {}, global = {} },
}
end
local function load_id_registry()
if id_registry then
return
end
id_registry = common.readJsonPage('数据:Gifting/gift_id_registry.json') or {}
registry_character_ids = id_registry.characters or {}
registry_item_ids = id_registry.items or {}
end
local function item_id_from_index(index)
load_id_registry()
local n = tonumber(index)
if not n then
return ''
end
return common.trim(registry_item_ids[n + 1] or '')
end
local function character_id_from_index(index)
load_id_registry()
local n = tonumber(index)
if not n then
return ''
end
return common.trim(registry_character_ids[n + 1] or '')
end
local function load_character_data()
if character_cache then
return
end
character_cache = common.readJsonPage('数据:Gifting/gift_preferences.json') or {}
character_records = character_cache.characters or {}
global_rules = character_cache.global or {}
tag_items = character_cache.tag_items or {}
load_id_registry()
character_ids = {}
for idx, record in ipairs(character_records) do
local cid = character_id_from_index(idx - 1)
if cid ~= '' then
character_ids[normalize_key(cid)] = idx
end
end
character_mapping = common.readJsonPage('数据:Gifting/gifting_mapping.json') or {
name_to_id = {},
id_to_name = {},
aliases = {},
overrides = {
name_to_id = {},
aliases = {},
},
}
end
local function load_item_data()
if item_cache then
return
end
item_cache = common.readJsonPage('数据:Gifting/gift_preferences_by_item.json') or {}
item_by_index = item_cache.items or {}
item_redirects = item_cache.item_redirects or {}
item_mapping = common.readJsonPage('数据:Item/item_mapping.json') or {
name_to_id = {},
id_to_name = {},
aliases = {},
overrides = {
name_to_id = {},
aliases = {},
},
}
end
local function find_character_record(key)
load_character_data()
local resolved = common.trim(key)
if resolved == '' then
resolved = common.getCurrentTitleText()
end
local normalized = normalize_key(resolved)
local idx = character_ids[normalized]
if not idx then
local override_id = character_mapping.overrides and character_mapping.overrides.name_to_id and character_mapping.overrides.name_to_id[normalized]
if override_id then
idx = character_ids[normalize_key(override_id)]
end
end
if not idx then
local override_alias = character_mapping.overrides and character_mapping.overrides.aliases and character_mapping.overrides.aliases[normalized]
if override_alias then
idx = character_ids[normalize_key(override_alias)]
end
end
if not idx then
local mapped_id = character_mapping.name_to_id and character_mapping.name_to_id[normalized]
if mapped_id then
idx = character_ids[normalize_key(mapped_id)]
end
end
if not idx then
local alias_id = character_mapping.aliases and character_mapping.aliases[normalized]
if alias_id then
idx = character_ids[normalize_key(alias_id)]
end
end
if not idx then
return nil
end
return character_records[idx], idx - 1
end
local function resolve_item_index(index)
local key = tostring(index)
if item_by_index[key] then
return key
end
local redirected = item_redirects and item_redirects[key]
if redirected then
local redirected_key = tostring(redirected)
if item_by_index[redirected_key] then
return redirected_key
end
end
return nil
end
local function find_item_record(key)
load_item_data()
load_id_registry()
local resolved = common.trim(key)
if resolved == '' then
resolved = common.getCurrentTitleText()
end
local normalized = normalize_key(resolved)
local item_id = ''
for idx, id in ipairs(registry_item_ids) do
if normalize_key(id) == normalized then
item_id = id
break
end
end
if item_id == '' then
local override_id = item_mapping.overrides and item_mapping.overrides.name_to_id and item_mapping.overrides.name_to_id[normalized]
if override_id and override_id ~= '' then
item_id = override_id
end
end
if item_id == '' then
local override_alias = item_mapping.overrides and item_mapping.overrides.aliases and item_mapping.overrides.aliases[normalized]
if override_alias and override_alias ~= '' then
item_id = override_alias
end
end
if item_id == '' then
local mapped_id = item_mapping.name_to_id and item_mapping.name_to_id[normalized]
if mapped_id and mapped_id ~= '' then
item_id = mapped_id
end
end
if item_id == '' then
local alias_id = item_mapping.aliases and item_mapping.aliases[normalized]
if alias_id and alias_id ~= '' then
item_id = alias_id
end
end
if item_id == '' then
return nil
end
local item_index = nil
for idx, id in ipairs(registry_item_ids) do
if id == item_id then
item_index = idx - 1
break
end
end
if item_index == nil then
return nil
end
local resolved_index = resolve_item_index(item_index)
if not resolved_index then
return nil
end
return item_by_index[resolved_index]
end
local function append_unique_indexes(values, seen, target)
if type(values) ~= 'table' then
return
end
for _, value in ipairs(values) do
local index = tonumber(value)
if index ~= nil and not seen[index] then
seen[index] = true
target[#target + 1] = index
end
end
end
local function expand_rule_items(rule)
local result = {}
local seen = {}
for _, tag in ipairs(rule.t or {}) do
append_unique_indexes(tag_items[tag], seen, result)
end
append_unique_indexes(rule.s, seen, result)
return result
end
local function build_character_summary(record)
local summary = empty_summary()
local global_seen = {
resonance = {}, special = {}, loved = {}, liked = {}, neutral = {}, disliked = {}, hated = {},
}
local personal_seen = {
resonance = {}, special = {}, loved = {}, liked = {}, neutral = {}, disliked = {}, hated = {},
}
for _, rule in ipairs(global_rules) do
local bucket = resolve_level_bucket(rule.l)
if bucket and summary[bucket] then
for _, item_idx in ipairs(expand_rule_items(rule)) do
if not global_seen[bucket][item_idx] then
global_seen[bucket][item_idx] = true
summary[bucket].global[#summary[bucket].global + 1] = item_idx
end
end
end
end
for _, rule in ipairs(record.p or {}) do
local bucket = resolve_level_bucket(rule.l)
if bucket and summary[bucket] then
for _, item_idx in ipairs(expand_rule_items(rule)) do
if not global_seen[bucket][item_idx] and not personal_seen[bucket][item_idx] then
personal_seen[bucket][item_idx] = true
summary[bucket].personal[#summary[bucket].personal + 1] = item_idx
end
end
end
end
return summary
end
local function get_summary_bucket(record, bucket)
if type(record) ~= 'table' then
return nil
end
local resolved_bucket = level_to_bucket[bucket] or normalize_key(bucket)
local summary = build_character_summary(record)
return summary[resolved_bucket]
end
local function item_label_from_index(item_index)
load_item_data()
local item_id = item_id_from_index(item_index)
if item_id == '' then
return ''
end
return common.trim(item_mapping.id_to_name and item_mapping.id_to_name[normalize_key(item_id)] or '')
end
local function character_label_from_index(character_index)
load_character_data()
local character_id = character_id_from_index(character_index)
if character_id == '' then
return ''
end
return common.trim(character_mapping.id_to_name and character_mapping.id_to_name[normalize_key(character_id)] or '')
end
local function join_indexes(values, label_resolver, fallback_resolver)
if type(values) ~= 'table' or #values == 0 then
return ''
end
local parts = {}
for _, value in ipairs(values) do
local idx = tonumber(value)
if idx ~= nil then
local label = label_resolver and label_resolver(idx) or ''
if label ~= '' then
parts[#parts + 1] = ('[[%s]]'):format(label)
else
local fallback = fallback_resolver and fallback_resolver(idx) or ''
if fallback ~= '' then
parts[#parts + 1] = fallback
end
end
end
end
return table.concat(parts, '、')
end
local function render_bucket(bucket_data, personal_label, global_label, label_resolver, fallback_resolver)
if type(bucket_data) ~= 'table' then
return ''
end
local parts = {}
local personal = join_indexes(bucket_data.personal, label_resolver, fallback_resolver)
local global = join_indexes(bucket_data.global, label_resolver, fallback_resolver)
if personal ~= '' then
parts[#parts + 1] = personal_label .. ':' .. personal
end
if global ~= '' then
parts[#parts + 1] = global_label .. ':' .. global
end
return table.concat(parts, '<br />')
end
function p.getField(frame)
local key = common.getArg(frame, 1, '')
local field = common.getArg(frame, 2, '')
if field == '' then
return ''
end
local record, character_index = find_character_record(key)
if not record then
return ''
end
if field == 'id' then
return character_id_from_index(character_index)
end
if field == 'name' then
return common.toText(record.n)
end
if field == 'name_en' then
return common.toText(record.en)
end
if field == 'character_type' then
return common.toText(record.t)
end
if field == 'personal_rules' then
return common.toText(record.p)
end
return common.toText(record[field])
end
function p.preferenceList(frame)
local key = common.getArg(frame, 1, '')
local field = common.getArg(frame, 2, '')
if field == '' then
return ''
end
local record = find_character_record(key)
if not record then
return ''
end
return render_bucket(get_summary_bucket(record, field), '个人喜好', '全局通用喜好', item_label_from_index, item_id_from_index)
end
function p.preferenceListByItem(frame)
local key = common.getArg(frame, 1, '')
local field = common.getArg(frame, 2, '')
if field == '' then
return ''
end
local record = find_item_record(key)
if not record then
return ''
end
local bucket = level_to_bucket[field] or normalize_key(field)
local short = bucket_to_short[bucket]
local compact_bucket = record.s and short and record.s[short] or nil
if type(compact_bucket) ~= 'table' then
return ''
end
local decoded = {
personal = compact_bucket.p or {},
global = compact_bucket.g or {},
}
return render_bucket(decoded, '个人喜好角色', '全局通用喜好角色', character_label_from_index, character_id_from_index)
end
return p