打开/关闭搜索
搜索
打开/关闭菜单
1K
5.2K
4
8.2K
星砂岛百科
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
上传文件
打开/关闭外观设置菜单
通知
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
user-interface-preferences
个人工具
创建账号
登录
本站正在进行早期测试,目前仍存在许多内容的缺失。
查看“︁模块:Shop”︁的源代码
来自星砂岛百科
查看
阅读
查看源代码
查看历史
associated-pages
模块
讨论
更多操作
←
模块:Shop
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:已验证邮箱用户
您没有权限编辑
模块
命名空间内的页面。
您必须确认您的电子邮件地址才能编辑页面。请通过
参数设置
设置并确认您的电子邮件地址。
您可以查看和复制此页面的源代码。
local common = require('Module:Common') local item_common = require('Module:ItemCommon') local item = require('Module:Item') local css = require('Module:CSS') local p = {} local SHOP_FIELD_MAP = { name = 'n', description = 'd', map_description = 'md', kind = 'k', open_duration = 'od', shop_template = 'st', festival_template = 'ft', location_names = 'ln', area_ids = 'a', sources = 'ss', entries = 'e', } local ENTRY_FIELD_MAP = { item_id = 'i', group = 'g', source = 's', price_value = 'pv', price_currency = 'pc', price_costs = 'ca', max_count = 'm', refresh_interval = 'r', condition = 'c', title_requirement = 'tr', discount = 'd', need_discount = 'nd', only_one = 'o', ui_sort = 'u', } local REVERSE_SHOP_KEY = 'sid' local DEFAULT_CURRENCY = 'Currency.Default' local SPECIAL_CURRENCY_TEMPLATES = { ['currency.default'] = 'Gold', ['item.gamecoin'] = 'Star', ['currency.star'] = 'Star', ['currency.exp'] = 'Exp', ['experience.default'] = 'Exp', ['exp.default'] = 'Exp', } local ITEM_TYPE_LABEL_FALLBACKS = { craft = '制作物', food = '食物', book = '书籍', clothing = '服饰', seed = '种子', plant = '植物', animal = '动物', collect = '采集物', mine = '矿石', tool = '工具', furniture = '家具', decoration = '装饰', light = '照明', vehicle = '载具', music = '唱片', emoji = '表情', consumable = '消耗品', dailyuse = '日用品', currency = '货币', } local ITEM_TYPE_GROUP_LABELS = { materials = '材料', plants = '种子与植物', food = '食品', books = '配方与书籍', clothing = '服饰', furniture = '家具与装饰', tools = '工具与设备', animals = '动物与农牧', vehicles = '载具', fun = '收藏与娱乐', currency = '货币', other = '其他', } local CATEGORY_FAMILY_RANKS = { ['素材'] = 10, ['种子'] = 20, ['肥料'] = 21, ['食谱'] = 30, ['配方'] = 31, ['图纸'] = 32, ['道具'] = 40, ['食品'] = 50, ['零食'] = 51, ['饮料'] = 52, ['饮品'] = 53, ['美食'] = 54, ['菜肴'] = 55, ['家具'] = 60, ['相框'] = 61, ['盆栽'] = 62, ['时装'] = 70, ['唱片'] = 80, ['杂志'] = 81, ['载具'] = 90, } local shop_data_cache local shop_mapping_cache local by_item_cache local get_entry_field local get_entry_item_id local get_entry_item_record local function normalize_key(value) return common.normalizeKey(value) end local function get_current_page_name() local title = mw.title.getCurrentTitle() if not title then return '' end return common.trim(title.text or '') end local function text_sort_value(value) return mw.ustring.lower(common.trim(common.toText(value))) end local function sanitize_display_text(value) local text = common.trim(common.toText(value)) if text == '' then return '' end text = mw.ustring.gsub(text, '<[^>]+>', '') return common.trim(text) end local function copy_array(values) local out = {} if type(values) ~= 'table' then return out end for _, value in ipairs(values) do out[#out + 1] = value end return out end local function parse_optional_number(value, default_value) local numeric = tonumber(value) if numeric == nil then return default_value end return numeric end local function starts_with(value, prefix) return value:sub(1, #prefix) == prefix end local function any_prefix(value, prefixes) for _, prefix in ipairs(prefixes) do if starts_with(value, prefix) then return true end end return false end local function any_contains(value, patterns) for _, pattern in ipairs(patterns) do if mw.ustring.find(value, pattern, 1, true) then return true end end return false end local function get_semantic_level_rank(value) local text = sanitize_display_text(value) if text == '' then return 999, '' end if mw.ustring.find(text, '初始', 1, true) then return 0, text end if mw.ustring.find(text, '见习', 1, true) then return 10, text end if mw.ustring.find(text, '初级', 1, true) then return 20, text end if mw.ustring.find(text, '中级', 1, true) then return 30, text end if mw.ustring.find(text, '高级', 1, true) then return 40, text end if mw.ustring.find(text, '专家', 1, true) then return 50, text end if mw.ustring.find(text, '资深', 1, true) then return 60, text end local added = mw.ustring.match(text, '新增(%d+)') if added then return 70 + (tonumber(added) or 0), text end local numeric_suffix = mw.ustring.match(text, '(%d+)$') if numeric_suffix then return 200 + (tonumber(numeric_suffix) or 0), text end return 999, text end local function detect_category_family(value) local text = sanitize_display_text(value) if text == '' then return '', '' end local family, suffix = mw.ustring.match(text, '^(.-)%-(.+)$') if family and family ~= '' then return family, suffix end for candidate, _ in pairs(CATEGORY_FAMILY_RANKS) do if mw.ustring.find(text, candidate, 1, true) then return candidate, text end end return '', text end local function get_category_sort_meta(value) local label = sanitize_display_text(value) if label == '' then return { family_rank = 0, family = '', level_rank = 0, suffix = '', label = '', } end local family, suffix = detect_category_family(label) local level_rank, normalized_suffix = get_semantic_level_rank(suffix) return { family_rank = CATEGORY_FAMILY_RANKS[family] or 999, family = text_sort_value(family), level_rank = level_rank, suffix = text_sort_value(normalized_suffix), label = text_sort_value(label), } end local function compare_category_meta(left_meta, right_meta) if left_meta.family_rank ~= right_meta.family_rank then return left_meta.family_rank < right_meta.family_rank end if left_meta.family ~= right_meta.family then return left_meta.family < right_meta.family end if left_meta.level_rank ~= right_meta.level_rank then return left_meta.level_rank < right_meta.level_rank end if left_meta.suffix ~= right_meta.suffix then return left_meta.suffix < right_meta.suffix end if left_meta.label ~= right_meta.label then return left_meta.label < right_meta.label end return false end local function is_special_condition_text(value) local text = sanitize_display_text(value) if text == '' then return false end return mw.ustring.find(text, '任务', 1, true) or mw.ustring.find(text, 'Mission.', 1, true) or mw.ustring.find(text, '存档', 1, true) or mw.ustring.find(text, 'FreeShop', 1, true) or mw.ustring.find(text, 'NotSell', 1, true) end local function is_special_title_requirement(value) local text = sanitize_display_text(value) if text == '' then return false end return text == '小岛之光' or text == '星砂传奇' end local function get_condition_sort_meta(entry) local title_requirement = sanitize_display_text(get_entry_field(entry, 'title_requirement') or '') local condition = sanitize_display_text(get_entry_field(entry, 'condition') or '') local discount = tonumber(get_entry_field(entry, 'discount')) or 0 local need_discount = get_entry_field(entry, 'need_discount') local parts = {} if title_requirement ~= '' then parts[#parts + 1] = title_requirement end if condition ~= '' then parts[#parts + 1] = condition end if discount ~= 0 then parts[#parts + 1] = '折扣值 ' .. tostring(math.floor(discount)) elseif need_discount then parts[#parts + 1] = '受折扣系统影响' end local bucket = 0 if #parts == 0 then bucket = 0 elseif is_special_condition_text(condition) or is_special_title_requirement(title_requirement) then bucket = 3 elseif title_requirement ~= '' then bucket = 2 else bucket = 1 end local title_rank = get_semantic_level_rank(title_requirement) return { bucket = bucket, title_rank = title_rank, title = text_sort_value(title_requirement), condition = text_sort_value(condition), display = #parts == 0 and '无' or table.concat(parts, '<br>'), } end local function compare_condition_meta(left_meta, right_meta) if left_meta.bucket ~= right_meta.bucket then return left_meta.bucket < right_meta.bucket end if left_meta.title_rank ~= right_meta.title_rank then return left_meta.title_rank < right_meta.title_rank end if left_meta.title ~= right_meta.title then return left_meta.title < right_meta.title end if left_meta.condition ~= right_meta.condition then return left_meta.condition < right_meta.condition end return false end local function compare_entry_type(left_entry, right_entry) local left_item_id = get_entry_item_id(left_entry) local right_item_id = get_entry_item_id(right_entry) local left_meta = item_common.getItemSortMeta(get_entry_item_record(left_entry), left_item_id) local right_meta = item_common.getItemSortMeta(get_entry_item_record(right_entry), right_item_id) if left_meta.type_rank ~= right_meta.type_rank then return left_meta.type_rank < right_meta.type_rank end if left_meta.type_family ~= right_meta.type_family then return left_meta.type_family < right_meta.type_family end if left_meta.item_type ~= right_meta.item_type then return left_meta.item_type < right_meta.item_type end return false end get_entry_item_id = function(entry) return common.trim(get_entry_field(entry, 'item_id') or '') end get_entry_item_record = function(entry) local item_id = get_entry_item_id(entry) if item_id == '' then return nil end return item_common.findItemRecord(item_id) end local function get_entry_type_label(entry, item_record) local record = item_record or get_entry_item_record(entry) local item_id = get_entry_item_id(entry) local meta = item_common.getItemSortMeta(record, item_id) local item_type = meta.item_type or '' local type_family = meta.type_family or '' local type_label = '' if type(record) == 'table' then type_label = sanitize_display_text(record.type_display or '') end local category_label = sanitize_display_text(get_entry_field(entry, 'group') or '') local function build_group(rank, key) return { rank = rank, key = key, label = ITEM_TYPE_GROUP_LABELS[key] or '其他', } end if any_prefix(item_type, { 'itemtype.book_sewing', 'itemtype.clothing_' }) or any_contains(type_label, { '时装', '发型', '脚部', '上装', '下装', '面具', '帽', '眼', '眉', '唇', '皮肤', '特征', '套装', '服饰' }) or any_contains(category_label, { '时装' }) then return build_group(50, 'clothing') end if any_prefix(item_type, { 'itemtype.collect_', 'itemtype.mine_', 'itemtype.craft_processedproduct', 'itemtype.craft_loom', 'itemtype.craft_fiberingot', 'itemtype.craft_semifinished', 'itemtype.craft_productmod', 'itemtype.craft_separate', }) or any_contains(type_label, { '材料', '木料', '竹料', '矿石', '矿产', '加工产物' }) or any_contains(category_label, { '素材' }) then return build_group(10, 'materials') end if type_family == 'seed' or type_family == 'plant' or any_contains(type_label, { '种子', '树苗', '花卉', '作物', '植物' }) or any_contains(category_label, { '种子' }) then return build_group(20, 'plants') end if type_family == 'book' or any_prefix(item_type, { 'itemtype.book_' }) or any_contains(type_label, { '配方', '图纸', '裁剪图', '食谱', '诗书', '杂志' }) or any_contains(category_label, { '配方', '图纸', '食谱' }) then return build_group(40, 'books') end if type_family == 'food' or any_prefix(item_type, { 'itemtype.food_' }) or any_contains(type_label, { '食品', '零食', '饮品', '饮料', '菜肴', '美食', '食材', '调料', '食物' }) or any_contains(category_label, { '食品', '零食', '饮品', '饮料', '菜肴', '美食' }) then return build_group(30, 'food') end if type_family == 'furniture' or type_family == 'decoration' or type_family == 'light' or any_contains(type_label, { '家具', '装饰', '相框', '盆栽', '灯' }) or any_contains(category_label, { '家具', '相框', '盆栽' }) then return build_group(60, 'furniture') end if any_prefix(item_type, { 'itemtype.craft_handcraft', 'itemtype.craft_workbench', 'itemtype.craft_manufacturefacility', 'itemtype.craft_functionfacility', 'itemtype.craft_collectfacility', 'itemtype.craft_breedingfacility', 'itemtype.craft_cookingfacility', 'itemtype.craft_conversionfacility', 'itemtype.craft_sewingtable', }) or type_family == 'tool' or type_family == 'dailyuse' or type_family == 'consumable' or type_family == 'mics' or type_family == 'electric' or type_family == 'electronics' or any_contains(type_label, { '工具', '设备', '遥控器' }) or any_contains(category_label, { '道具' }) then return build_group(70, 'tools') end if type_family == 'animal' or any_contains(type_label, { '动物', '鱼类', '昆虫', '饲料' }) then return build_group(80, 'animals') end if type_family == 'vehicle' or any_contains(type_label, { '载具' }) or any_contains(category_label, { '载具' }) then return build_group(90, 'vehicles') end if type_family == 'music' or type_family == 'emoji' or any_contains(type_label, { '唱片', '舞蹈', '表情', '扭蛋' }) or any_contains(category_label, { '唱片' }) then return build_group(100, 'fun') end if type_family == 'currency' then return build_group(110, 'currency') end if type_label ~= '' and ITEM_TYPE_LABEL_FALLBACKS[type_family] then return { rank = 999, key = type_family ~= '' and type_family or 'other', label = ITEM_TYPE_LABEL_FALLBACKS[type_family], } end return build_group(999, 'other') end local function load_shop_data() if shop_data_cache then return end local raw_data raw_data, shop_mapping_cache = item_common.loadDomainData('数据:Shop/shop_index.json', '数据:Shop/shop_mapping.json') if type(raw_data) == 'table' and type(raw_data.records) == 'table' then shop_data_cache = raw_data.records else shop_data_cache = raw_data or {} end local raw_reverse = common.loadJsonData('数据:Shop/shop_by_item.json') or {} if type(raw_reverse) == 'table' and type(raw_reverse.records) == 'table' then by_item_cache = raw_reverse.records else by_item_cache = raw_reverse or {} end end local function get_shop_field(record, field) if type(record) ~= 'table' then return nil end local short_key = SHOP_FIELD_MAP[field] or field if record[short_key] ~= nil then return record[short_key] end return record[field] end get_entry_field = function(entry, field) if type(entry) ~= 'table' then return nil end local short_key = ENTRY_FIELD_MAP[field] or field if entry[short_key] ~= nil then return entry[short_key] end return entry[field] end local function has_items(value) if type(value) ~= 'table' then return false end for _, _ in ipairs(value) do return true end return false end local function resolve_shop_id_from_mapping(value) if type(shop_mapping_cache) ~= 'table' then return '' end local normalized = normalize_key(value) if normalized == '' then return '' end if shop_mapping_cache.name_to_id and shop_mapping_cache.name_to_id[normalized] then return shop_mapping_cache.name_to_id[normalized] end if shop_mapping_cache.aliases and shop_mapping_cache.aliases[normalized] then return shop_mapping_cache.aliases[normalized] end return '' end local function find_shop_record(key) load_shop_data() local resolved = common.trim(key) if resolved == '' then resolved = common.getCurrentTitleText() end local normalized = normalize_key(resolved) if shop_data_cache[normalized] then return shop_data_cache[normalized], resolved end local mapped_id = resolve_shop_id_from_mapping(resolved) if mapped_id ~= '' then local mapped_key = normalize_key(mapped_id) if shop_data_cache[mapped_key] then return shop_data_cache[mapped_key], mapped_id end end return nil, '' end local function resolve_item_id(key) local record = item_common.findItemRecord(key) if type(record) == 'table' and common.trim(record.id or '') ~= '' then return common.trim(record.id) end return common.trim(key) end local function get_entries_for_item(key) load_shop_data() local item_id = resolve_item_id(key) if item_id == '' then return {} end return by_item_cache[normalize_key(item_id)] or {} end local function render_shop_link(shop_record, shop_id) local display_name = common.trim(get_shop_field(shop_record, 'name') or shop_id) if display_name == '' then display_name = common.trim(shop_id) end if display_name == '' then return '' end return ('[[%s]]'):format(display_name) end local function render_currency_item(frame, currency_id, count) local resolved_currency = common.trim(currency_id) if resolved_currency == '' then return '' end local suffix = '' if tonumber(count) and tonumber(count) > 0 then suffix = tostring(math.floor(tonumber(count))) end return item.renderItemWithArgs(frame, { resolved_currency, suffix, }) end local function render_template_currency(frame, template_title, count) return frame:expandTemplate{ title = template_title, args = { tostring(math.floor(tonumber(count) or 0)) }, } end local function render_currency_value(frame, currency_id, count) local normalized = normalize_key(currency_id) local template_title = SPECIAL_CURRENCY_TEMPLATES[normalized] if template_title then return render_template_currency(frame, template_title, count) end return render_currency_item(frame, currency_id, count) end local function render_price(frame, entry) local costs = get_entry_field(entry, 'price_costs') if has_items(costs) then local parts = {} for _, cost in ipairs(costs) do if type(cost) == 'table' and common.trim(cost[1] or '') ~= '' then parts[#parts + 1] = render_currency_value(frame, cost[1], cost[2]) end end return table.concat(parts, '') end local currency = common.trim(get_entry_field(entry, 'price_currency') or DEFAULT_CURRENCY) local value = tonumber(get_entry_field(entry, 'price_value')) or 0 if currency == '' or currency == DEFAULT_CURRENCY then if value <= 0 then return '免费' end return render_template_currency(frame, 'Gold', value) end return render_currency_value(frame, currency, value) end local function format_refresh(refresh_interval) local refresh = tonumber(refresh_interval) or 0 if refresh == -1 then return '不刷新' end if refresh == 1 then return '每日刷新' end if refresh > 1 then return tostring(math.floor(refresh)) .. ' 天刷新' end return '' end local function get_refresh_meta(refresh_interval) local refresh = tonumber(refresh_interval) or 0 if refresh == -1 then return { key = 'never', prefix = '永久', text = '不刷新', } end if refresh == 1 then return { key = 'daily', prefix = '每日', text = '每日刷新', } end if refresh > 1 then local days = tostring(math.floor(refresh)) return { key = 'every:' .. days, prefix = '每' .. days .. '天', text = days .. ' 天刷新', } end return { key = 'none', prefix = '', text = '', } end local function format_limit(entry) local max_count = tonumber(get_entry_field(entry, 'max_count')) or 0 if max_count == -1 or max_count == 0 then if get_entry_field(entry, 'only_one') then return '不限购<br>单次仅购 1' end return '不限购' end if get_entry_field(entry, 'only_one') then return '限购 ' .. tostring(math.floor(max_count)) .. '<br>单次仅购 1' end return '限购 ' .. tostring(math.floor(max_count)) end local function format_combined_limit(entry, refresh_prefix) local max_count = tonumber(get_entry_field(entry, 'max_count')) or 0 local prefix = common.trim(refresh_prefix or '') local text = '' if max_count == -1 or max_count == 0 then text = prefix ~= '' and (prefix .. '不限购') or '不限购' else text = (prefix ~= '' and (prefix .. '限购 ') or '限购 ') .. tostring(math.floor(max_count)) end if get_entry_field(entry, 'only_one') and max_count ~= 1 then text = text .. '<br>单次仅购 1' end return text end local function get_inventory_limit_layout(entries) local shared_refresh_key = nil local shared_refresh_prefix = '' for _, entry in ipairs(entries) do local refresh_meta = get_refresh_meta(get_entry_field(entry, 'refresh_interval')) if refresh_meta.key == 'none' then return { merged = false, } end if shared_refresh_key == nil then shared_refresh_key = refresh_meta.key shared_refresh_prefix = refresh_meta.prefix elseif shared_refresh_key ~= refresh_meta.key then return { merged = false, } end end if shared_refresh_key == nil then return { merged = false, } end return { merged = true, header = '购买限制', refresh_key = shared_refresh_key, refresh_prefix = shared_refresh_prefix, } end local function render_item_cell(frame, entry) local item_id = get_entry_item_id(entry) if item_id == '' then return '' end return item.renderItemWithArgs(frame, { item_id, class = 'block' }) end local function compare_inventory_entries(left_entry, right_entry) local left_group = get_entry_type_label(left_entry, get_entry_item_record(left_entry)) local right_group = get_entry_type_label(right_entry, get_entry_item_record(right_entry)) if left_group.rank ~= right_group.rank then return left_group.rank < right_group.rank end if left_group.key ~= right_group.key then return left_group.key < right_group.key end if compare_entry_type(left_entry, right_entry) then return true end if compare_entry_type(right_entry, left_entry) then return false end local left_category = get_category_sort_meta(get_entry_field(left_entry, 'group') or '') local right_category = get_category_sort_meta(get_entry_field(right_entry, 'group') or '') if compare_category_meta(left_category, right_category) then return true end if compare_category_meta(right_category, left_category) then return false end local left_condition = get_condition_sort_meta(left_entry) local right_condition = get_condition_sort_meta(right_entry) if compare_condition_meta(left_condition, right_condition) then return true end if compare_condition_meta(right_condition, left_condition) then return false end local left_ui_sort = parse_optional_number(get_entry_field(left_entry, 'ui_sort'), 999999) local right_ui_sort = parse_optional_number(get_entry_field(right_entry, 'ui_sort'), 999999) if left_ui_sort ~= right_ui_sort then return left_ui_sort < right_ui_sort end local left_item_id = get_entry_item_id(left_entry) local right_item_id = get_entry_item_id(right_entry) if left_item_id ~= right_item_id then return item_common.compareItemKeys(left_item_id, right_item_id, get_entry_item_record(left_entry), get_entry_item_record(right_entry)) end local left_price = tonumber(get_entry_field(left_entry, 'price_value')) or 0 local right_price = tonumber(get_entry_field(right_entry, 'price_value')) or 0 if left_price ~= right_price then return left_price < right_price end return text_sort_value(get_entry_field(left_entry, 'source') or '') < text_sort_value(get_entry_field(right_entry, 'source') or '') end local function compare_sold_by_entries(left_entry, right_entry) local left_condition = get_condition_sort_meta(left_entry) local right_condition = get_condition_sort_meta(right_entry) if compare_condition_meta(left_condition, right_condition) then return true end if compare_condition_meta(right_condition, left_condition) then return false end local left_price = tonumber(get_entry_field(left_entry, 'price_value')) or 0 local right_price = tonumber(get_entry_field(right_entry, 'price_value')) or 0 if left_price ~= right_price then return left_price < right_price end local left_shop = text_sort_value(left_entry[REVERSE_SHOP_KEY] or '') local right_shop = text_sort_value(right_entry[REVERSE_SHOP_KEY] or '') if left_shop ~= right_shop then return left_shop < right_shop end return false end local function sort_entries(entries, comparator) local ordered = copy_array(entries) if #ordered > 1 then table.sort(ordered, comparator) end return ordered end local function render_inventory_group_table(frame, entries) local limit_layout = get_inventory_limit_layout(entries) local out = {} out[#out + 1] = '{| class="wikitable"' out[#out + 1] = '! 物品' out[#out + 1] = '! 分类' out[#out + 1] = '! 价格' if limit_layout.merged then out[#out + 1] = '! ' .. limit_layout.header else out[#out + 1] = '! 限购' out[#out + 1] = '! 刷新' end out[#out + 1] = '! 条件' for _, entry in ipairs(entries) do local category = sanitize_display_text(get_entry_field(entry, 'group') or '') local condition_meta = get_condition_sort_meta(entry) local refresh_text = format_refresh(get_entry_field(entry, 'refresh_interval')) if category == '' then category = '未分组' end if refresh_text == '' then refresh_text = '—' end out[#out + 1] = '|-' out[#out + 1] = '| ' .. render_item_cell(frame, entry) out[#out + 1] = '| ' .. category out[#out + 1] = '| ' .. render_price(frame, entry) if limit_layout.merged then out[#out + 1] = '| ' .. format_combined_limit(entry, limit_layout.refresh_prefix) else out[#out + 1] = '| ' .. format_limit(entry) out[#out + 1] = '| ' .. refresh_text end out[#out + 1] = '| ' .. condition_meta.display end out[#out + 1] = '|}' return table.concat(out, '\n') end local function render_sold_by_table(frame, entries) if not has_items(entries) then return '' end load_shop_data() local ordered_entries = sort_entries(entries, compare_sold_by_entries) local out = {} out[#out + 1] = css.quickCall('Item') or '' out[#out + 1] = '{| class="wikitable"' out[#out + 1] = '! 商店' out[#out + 1] = '! 价格' out[#out + 1] = '! 限购' out[#out + 1] = '! 刷新' out[#out + 1] = '! 条件' for _, entry in ipairs(ordered_entries) do local shop_id = common.trim(entry[REVERSE_SHOP_KEY] or '') local shop_record = shop_data_cache[normalize_key(shop_id)] local shop_cell = render_shop_link(shop_record, shop_id) local price_cell = render_price(frame, entry) local limit_cell = format_limit(entry) local refresh_cell = format_refresh(get_entry_field(entry, 'refresh_interval')) local condition_cell = get_condition_sort_meta(entry).display if refresh_cell == '' then refresh_cell = '—' end out[#out + 1] = '|-' out[#out + 1] = '| ' .. shop_cell out[#out + 1] = '| ' .. price_cell out[#out + 1] = '| ' .. limit_cell out[#out + 1] = '| ' .. refresh_cell out[#out + 1] = '| ' .. condition_cell end out[#out + 1] = '|}' return table.concat(out, '\n') end local function render_inventory_table(frame, shop_record) local entries = get_shop_field(shop_record, 'entries') if not has_items(entries) then return '' end local ordered_entries = sort_entries(entries, compare_inventory_entries) local grouped = {} local ordered_groups = {} for _, entry in ipairs(ordered_entries) do local item_record = get_entry_item_record(entry) local group_meta = get_entry_type_label(entry, item_record) local group_key = group_meta.key local group = grouped[group_key] if not group then group = { key = group_key, label = group_meta.label, rank = group_meta.rank, entries = {}, } grouped[group_key] = group ordered_groups[#ordered_groups + 1] = group end group.entries[#group.entries + 1] = entry end local out = {} out[#out + 1] = css.quickCall('Item') or '' table.sort(ordered_groups, function(left_group, right_group) if left_group.rank ~= right_group.rank then return left_group.rank < right_group.rank end return left_group.key < right_group.key end) for _, group in ipairs(ordered_groups) do out[#out + 1] = '<h3>' .. group.label .. '</h3>' out[#out + 1] = render_inventory_group_table(frame, group.entries) end return table.concat(out, '\n') end local function render_shop_kind(shop_record) local kind = common.trim(get_shop_field(shop_record, 'kind') or '') if kind == 'festival' then return '节日商店' end if kind == 'shop' then return '普通商店' end return kind end local function render_shop_sources(shop_record) local sources = get_shop_field(shop_record, 'sources') if type(sources) ~= 'table' then return '' end local labels = { festival = '节日商店', shop = '商店', npc = 'NPC 货架', } local parts = {} for _, source in ipairs(sources) do local key = common.trim(source) if key ~= '' then parts[#parts + 1] = labels[key] or key end end return table.concat(parts, ' / ') end local function render_shop_locations(shop_record) local location_names = get_shop_field(shop_record, 'location_names') if type(location_names) ~= 'table' then return '' end local parts = {} for _, name in ipairs(location_names) do local text = common.trim(name) if text ~= '' then parts[#parts + 1] = text end end return table.concat(parts, '<br>') end local function has_shop_source(shop_record, expected_source) local sources = get_shop_field(shop_record, 'sources') if type(sources) ~= 'table' then return false end local expected = common.trim(expected_source) if expected == '' then return false end for _, source in ipairs(sources) do if common.trim(source) == expected then return true end end return false end local function render_shop_area_ids(shop_record) local area_ids = get_shop_field(shop_record, 'area_ids') if type(area_ids) ~= 'table' then return '' end local parts = {} for _, area_id in ipairs(area_ids) do local text = common.trim(area_id) if text ~= '' then parts[#parts + 1] = '<code>' .. mw.text.nowiki(text) .. '</code>' end end return table.concat(parts, '<br>') end local function render_shop_area_count(shop_record) local area_ids = get_shop_field(shop_record, 'area_ids') if not has_items(area_ids) then return '0' end local count = 0 for _, _ in ipairs(area_ids) do count = count + 1 end return tostring(count) end local function render_shop_template_refs(shop_record) local refs = {} local shop_template = common.trim(get_shop_field(shop_record, 'shop_template') or '') local festival_template = common.trim(get_shop_field(shop_record, 'festival_template') or '') if shop_template ~= '' then refs[#refs + 1] = '<code>' .. mw.text.nowiki(shop_template) .. '</code>' end if festival_template ~= '' then refs[#refs + 1] = '<code>' .. mw.text.nowiki(festival_template) .. '</code>' end return table.concat(refs, '<br>') end local function render_shop_entry_count(shop_record) local entries = get_shop_field(shop_record, 'entries') if not has_items(entries) then return '0' end local count = 0 for _, _ in ipairs(entries) do count = count + 1 end return tostring(count) end local function add_currency_id(ordered_ids, seen_ids, currency_id) local resolved = common.trim(currency_id) if resolved == '' then return end local normalized = normalize_key(resolved) if seen_ids[normalized] then return end seen_ids[normalized] = true ordered_ids[#ordered_ids + 1] = resolved end local function render_currency_summary(frame, shop_record) local entries = get_shop_field(shop_record, 'entries') if not has_items(entries) then return '' end local ordered_ids = {} local seen_ids = {} for _, entry in ipairs(entries) do local costs = get_entry_field(entry, 'price_costs') if has_items(costs) then for _, cost in ipairs(costs) do if type(cost) == 'table' then add_currency_id(ordered_ids, seen_ids, cost[1]) end end else add_currency_id(ordered_ids, seen_ids, get_entry_field(entry, 'price_currency') or DEFAULT_CURRENCY) end end local parts = {} for _, currency_id in ipairs(ordered_ids) do local normalized = normalize_key(currency_id) if normalized == 'currency.default' then parts[#parts + 1] = '金币' elseif normalized == 'item.gamecoin' or normalized == 'currency.star' then parts[#parts + 1] = '星砂' elseif normalized == 'currency.exp' or normalized == 'experience.default' or normalized == 'exp.default' then parts[#parts + 1] = '经验' else parts[#parts + 1] = item.renderItemWithArgs(frame, { currency_id }) end end return table.concat(parts, '<br>') end local function render_shop_auto_categories(shop_record) local categories = { '[[分类:商店建筑]]', } local kind = common.trim(get_shop_field(shop_record, 'kind') or '') if kind == 'festival' then categories[#categories + 1] = '[[分类:节日商店]]' end if has_shop_source(shop_record, 'npc') then categories[#categories + 1] = '[[分类:NPC商店]]' end return table.concat(categories, '') end function p.getShopField(frame) local key = common.getArg(frame, 1, '') local field = common.getArg(frame, 2, '') if field == '' then return '' end local shop_record = find_shop_record(key) if not shop_record then return '' end if field == 'kind_display' then return render_shop_kind(shop_record) end if field == 'name_display' then local name = common.trim(get_shop_field(shop_record, 'name') or '') if name ~= '' then return name end return get_current_page_name() end if field == 'source_display' then return render_shop_sources(shop_record) end if field == 'location_display' then return render_shop_locations(shop_record) end if field == 'area_ids_display' then return render_shop_area_ids(shop_record) end if field == 'area_count' then return render_shop_area_count(shop_record) end if field == 'template_refs_display' then return render_shop_template_refs(shop_record) end if field == 'entry_count' then return render_shop_entry_count(shop_record) end if field == 'currency_summary' then return render_currency_summary(frame, shop_record) end if field == 'auto_categories' then return render_shop_auto_categories(shop_record) end return common.toText(get_shop_field(shop_record, field)) end function p.renderSoldBy(frame) local key = common.getArg(frame, 1, '') local entries = get_entries_for_item(key) if not has_items(entries) then return '暂无商店出售记录。' end return render_sold_by_table(frame, entries) end function p.renderShopInventory(frame) local key = common.getArg(frame, 1, '') local shop_record = find_shop_record(key) if not shop_record then return '未找到商店数据。' end local rendered = render_inventory_table(frame, shop_record) if rendered == '' then return '暂无商店库存记录。' end return rendered end return p
该页面嵌入的页面:
模板:Documentation subpage
(
查看源代码
)
模块:Shop/doc
(
查看源代码
)
返回
模块:Shop
。
查看“︁模块:Shop”︁的源代码
来自星砂岛百科