打开/关闭搜索
搜索
打开/关闭菜单
1K
5.2K
4
8.2K
星砂岛百科
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
上传文件
打开/关闭外观设置菜单
通知
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
user-interface-preferences
个人工具
创建账号
登录
本站正在进行早期测试,目前仍存在许多内容的缺失。
查看“︁模块:Schedule”︁的源代码
来自星砂岛百科
查看
阅读
查看源代码
查看历史
associated-pages
模块
讨论
更多操作
←
模块:Schedule
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:已验证邮箱用户
您没有权限编辑
模块
命名空间内的页面。
您必须确认您的电子邮件地址才能编辑页面。请通过
参数设置
设置并确认您的电子邮件地址。
您可以查看和复制此页面的源代码。
local common = require('Module:Common') local p = {} local schedule_data local mapping local location_labels local source_order = { regular = 1, special = 2, living_together = 3, } local source_labels = { regular = '常规日程', special = '特殊日程', living_together = '同居日程', } local month_labels = { spring = '春季', summer = '夏季', autumn = '秋季', winter = '冬季', } local weekday_labels = { monday = '周一', tuesday = '周二', wednesday = '周三', thursday = '周四', friday = '周五', saturday = '周六', sunday = '周日', } local season_number_labels = { ['1'] = '春季', ['2'] = '夏季', ['3'] = '秋季', ['4'] = '冬季', } local weekday_number_labels = { ['0'] = '周日', ['1'] = '周一', ['2'] = '周二', ['3'] = '周三', ['4'] = '周四', ['5'] = '周五', ['6'] = '周六', } local weather_labels = { Rain = '雨天', ClearSky = '晴天', Snow = '雪天', } local festival_labels = { ['Festival.SpringFestivalActivity_POI_AfterFestival'] = '春节前', ['Festival.SpringFestivalActivity_POI_InFestival'] = '春节期间', } local buildable_labels = { BuildableRegion_Boat = '渡口建造', } local compare_op_labels = { Equal = '等于', GreatOrEqualThan = '大于等于', GreatThan = '大于', LessOrEqualThan = '小于等于', LessThan = '小于', Between = '介于', } local generic_condition_descs = { ['On Raining Days'] = true, ['雨天日程'] = true, ['雨雪天'] = true, ['雨雪天日程'] = true, } local generic_mission_goals = { ['执行互动'] = true, } local function default_mapping() return { name_to_id = {}, id_to_name = {}, aliases = {}, overrides = { name_to_id = {}, aliases = {}, }, } end local function normalize_key(value) return common.normalizeKey(value) 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 append_unique(target, values) if type(target) ~= 'table' or type(values) ~= 'table' then return end local seen = {} for _, value in ipairs(target) do seen[tostring(value)] = true end for _, value in ipairs(values) do local key = tostring(value) if not seen[key] then target[#target + 1] = value seen[key] = true end end end local function sort_text_list(values, order_map) table.sort(values, function(a, b) local a_key = tostring(a) local b_key = tostring(b) local a_rank = order_map and order_map[a_key] or nil local b_rank = order_map and order_map[b_key] or nil if a_rank and b_rank and a_rank ~= b_rank then return a_rank < b_rank end if a_rank and not b_rank then return true end if b_rank and not a_rank then return false end return a_key < b_key end) end local function sort_number_list(values) table.sort(values, function(a, b) return tonumber(a) < tonumber(b) end) end local function load_data() if schedule_data then return end schedule_data = common.loadJsonData('数据:Character/character_schedule_index.json') or {} mapping = common.loadJsonData('数据:Character/character_mapping.json') or default_mapping() location_labels = common.loadJsonData('数据:Character/schedule_location_labels.json') or {} end local function find_record(key) load_data() local resolved = common.trim(key) if resolved == '' then resolved = common.getCurrentTitleText() end local normalized = normalize_key(resolved) if schedule_data[normalized] then return schedule_data[normalized] end local override_id = mapping.overrides and mapping.overrides.name_to_id and mapping.overrides.name_to_id[normalized] if override_id and schedule_data[normalize_key(override_id)] then return schedule_data[normalize_key(override_id)] end local override_alias = mapping.overrides and mapping.overrides.aliases and mapping.overrides.aliases[normalized] if override_alias and schedule_data[normalize_key(override_alias)] then return schedule_data[normalize_key(override_alias)] end local mapped_id = mapping.name_to_id and mapping.name_to_id[normalized] if mapped_id and schedule_data[normalize_key(mapped_id)] then return schedule_data[normalize_key(mapped_id)] end local alias_id = mapping.aliases and mapping.aliases[normalized] if alias_id and schedule_data[normalize_key(alias_id)] then return schedule_data[normalize_key(alias_id)] end return nil end local function list_key(values) if type(values) ~= 'table' then return '' end local out = {} for _, value in ipairs(values) do out[#out + 1] = tostring(value) end return table.concat(out, ',') end local function build_condition_key(items) if type(items) ~= 'table' then return '' end local out = {} for _, item in ipairs(items) do if type(item) == 'table' then out[#out + 1] = table.concat({ common.trim(item.type), tostring(item.reverse), common.trim(item.dest_type), common.trim(item.key), common.trim(item.tag), common.trim(item.op), common.trim(item.value), tostring(item.check_day), tostring(item.check_month), tostring(item.check_weekday), tostring(item.check_year), common.trim(item.year_op), common.trim(item.year_value), }, '~') end end return table.concat(out, '||') end local function build_slot_key(slots) if type(slots) ~= 'table' then return '' end local out = {} for _, slot in ipairs(slots) do if type(slot) == 'table' then local primary_action = slot.primary_action local primary_template = '' if type(primary_action) == 'table' then primary_template = common.trim(primary_action.template) end out[#out + 1] = table.concat({ common.trim(slot.begin_time), common.trim(slot.end_time), common.trim(slot.kind), common.trim(slot.summary), common.trim(slot.mission_template), primary_template, }, '~') end end return table.concat(out, '||') end local function clone_variant(variant) return { source = common.trim(variant.source), schedule_id = common.trim(variant.schedule_id), months = copy_array(variant.months), month_labels = copy_array(variant.month_labels), weekdays = copy_array(variant.weekdays), weekday_labels = copy_array(variant.weekday_labels), days = copy_array(variant.days), priority = variant.priority, condition_desc = common.trim(variant.condition_desc), condition_summary = variant.condition_summary or {}, condition_raw = variant.condition_raw or {}, slots = variant.slots or {}, } end local function merge_variants(variants) local grouped = {} local order = {} if type(variants) ~= 'table' then return order end for _, variant in ipairs(variants) do if type(variant) == 'table' then local key = table.concat({ common.trim(variant.source), common.trim(variant.schedule_id), list_key(variant.months), list_key(variant.days), common.trim(variant.condition_desc), build_condition_key(variant.condition_summary), build_slot_key(variant.slots), }, '|') if not grouped[key] then grouped[key] = clone_variant(variant) order[#order + 1] = grouped[key] else append_unique(grouped[key].weekdays, variant.weekdays or {}) append_unique(grouped[key].weekday_labels, variant.weekday_labels or {}) append_unique(grouped[key].months, variant.months or {}) append_unique(grouped[key].month_labels, variant.month_labels or {}) append_unique(grouped[key].days, variant.days or {}) end end end for _, variant in ipairs(order) do sort_number_list(variant.months) sort_number_list(variant.weekdays) sort_number_list(variant.days) sort_text_list(variant.month_labels, { spring = 1, summer = 2, autumn = 3, winter = 4, }) sort_text_list(variant.weekday_labels, { monday = 1, tuesday = 2, wednesday = 3, thursday = 4, friday = 5, saturday = 6, sunday = 7, }) end table.sort(order, function(a, b) local a_source = source_order[a.source] or 99 local b_source = source_order[b.source] or 99 if a_source ~= b_source then return a_source < b_source end local a_month = tonumber(a.months[1] or 99) or 99 local b_month = tonumber(b.months[1] or 99) or 99 if a_month ~= b_month then return a_month < b_month end local a_weekday = tonumber(a.weekdays[1] or 99) or 99 local b_weekday = tonumber(b.weekdays[1] or 99) or 99 if a_weekday ~= b_weekday then return a_weekday < b_weekday end local a_day = tonumber(a.days[1] or 99) or 99 local b_day = tonumber(b.days[1] or 99) or 99 if a_day ~= b_day then return a_day < b_day end local a_desc = common.trim(a.condition_desc) local b_desc = common.trim(b.condition_desc) if a_desc ~= b_desc then return a_desc < b_desc end return common.trim(a.schedule_id) < common.trim(b.schedule_id) end) return order end local function map_labels(values, label_map) if type(values) ~= 'table' then return {} end local out = {} for _, value in ipairs(values) do local text = common.trim(value) if text ~= '' then out[#out + 1] = label_map[text] or text end end return out end local function join_parts(values) if type(values) ~= 'table' or #values == 0 then return '' end return table.concat(values, '、') end local function unique_texts(values) local out = {} local seen = {} if type(values) ~= 'table' then return out end for _, value in ipairs(values) do local text = common.trim(value) if text ~= '' and not seen[text] then out[#out + 1] = text seen[text] = true end end return out end local function rank_candidates(candidates) local ranked = {} if type(candidates) ~= 'table' then return ranked end for _, candidate in ipairs(candidates) do if type(candidate) == 'table' then ranked[#ranked + 1] = candidate end end table.sort(ranked, function(a, b) local a_weight = tonumber(a.weight or 0) or 0 local b_weight = tonumber(b.weight or 0) or 0 if a_weight ~= b_weight then return a_weight > b_weight end local a_score = tonumber(a.score or 0) or 0 local b_score = tonumber(b.score or 0) or 0 if a_score ~= b_score then return a_score > b_score end return common.trim(a.template) > common.trim(b.template) end) return ranked end local function get_top_candidates(candidates) local ranked = rank_candidates(candidates) if #ranked == 0 then return ranked, {} end local first = ranked[1] local top_weight = tonumber(first.weight or 0) or 0 local top_score = tonumber(first.score or 0) or 0 local top = {} for _, candidate in ipairs(ranked) do local weight = tonumber(candidate.weight or 0) or 0 local score = tonumber(candidate.score or 0) or 0 if weight == top_weight and score == top_score then top[#top + 1] = candidate else break end end return ranked, top end local function clean_condition_desc(value) local text = common.trim(value) text = mw.ustring.gsub(text, '^%*+', '') return common.trim(text) end local function should_use_structured_condition(desc) local cleaned = clean_condition_desc(desc) if cleaned == '' then return true end if generic_condition_descs[cleaned] then return true end if mw.ustring.find(cleaned, '[A-Za-z]') and not mw.ustring.find(cleaned, '[一-龥]') then return true end return false end local function describe_compare_range(op, value, min_value, max_value, label_map, suffix) local resolved_op = common.trim(op) local resolved_value = common.trim(value) local resolved_min = common.trim(min_value) local resolved_max = common.trim(max_value) local resolved_suffix = suffix or '' local function map_value(raw) local key = common.trim(raw) if key == '' then return '' end if label_map and label_map[key] then return label_map[key] end return key .. resolved_suffix end if resolved_op == 'Equal' and resolved_value ~= '' then return map_value(resolved_value) end if resolved_op == 'Between' and resolved_min ~= '' and resolved_max ~= '' then local left = map_value(resolved_min) local right = map_value(resolved_max) if label_map then return left .. ' - ' .. right end return resolved_min .. ' - ' .. resolved_max .. resolved_suffix end local compare_label = compare_op_labels[resolved_op] or resolved_op if compare_label ~= '' and resolved_value ~= '' then return compare_label .. map_value(resolved_value) end return '' end local function build_apply_text(variant) local parts = {} local months = map_labels(variant.month_labels, month_labels) local weekdays = map_labels(variant.weekday_labels, weekday_labels) local days = {} for _, day in ipairs(variant.days or {}) do local value = common.trim(day) if value ~= '' then days[#days + 1] = value .. '日' end end if #months > 0 then parts[#parts + 1] = join_parts(months) end if #weekdays > 0 then parts[#parts + 1] = join_parts(weekdays) end if #days > 0 then parts[#parts + 1] = join_parts(days) end return table.concat(parts, ' / ') end local function describe_condition_item(item) if type(item) ~= 'table' then return '' end if item.type == 'weather_today' then local dest_type = common.trim(item.dest_type) local label = weather_labels[dest_type] or dest_type if label ~= '' then if item.reverse then return '非' .. label end return label end return '天气条件' end if item.type == 'entity_data_check_string' then local key = common.trim(item.key) local op = common.trim(item.op) local value = common.trim(item.value) if key == 'Schedule_Typhoon' and value == '1' then if item.reverse then return '非台风天气' end return '台风天气' end if key ~= '' and value ~= '' then local prefix = item.reverse and '不满足:' or '' if op ~= '' then return prefix .. key .. ' ' .. op .. ' ' .. value end return prefix .. key .. ' = ' .. value end end if item.type == 'npc_affection_star' then local value = common.trim(item.value) if value == '' then return item.reverse and '好感条件不满足' or '好感条件' end local op = common.trim(item.op) if op == 'GreatOrEqualThan' then return item.reverse and ('好感度未达到 ' .. value .. ' 心') or ('好感度达到 ' .. value .. ' 心') end if op == 'Equal' then return item.reverse and ('好感度不为 ' .. value .. ' 心') or ('好感度为 ' .. value .. ' 心') end local compare_label = compare_op_labels[op] or op if compare_label ~= '' then return item.reverse and ('好感条件不满足 ' .. compare_label .. ' ' .. value .. ' 心') or ('好感度 ' .. compare_label .. ' ' .. value .. ' 心') end return item.reverse and '好感条件不满足' or '好感条件' end if item.type == 'calendar_now_is_festival' then local festival_template = common.trim(item.festival_template) local label = festival_labels[festival_template] or festival_template if label ~= '' then if item.reverse then return '非' .. label end return label end return item.reverse and '非节庆期间' or '节庆期间' end if item.type == 'buildable_region_check_completed' then local template_name = common.trim(item.template) local label = buildable_labels[template_name] or template_name if label ~= '' then if item.reverse then return label .. '未完成' end return label .. '已完成' end return item.reverse and '建筑条件未完成' or '建筑条件已完成' end if item.type == 'check_has_owner' then if item.reverse then return '未被收养' end return '已被收养' end if item.type == 'time_check_date' then local parts = {} if item.check_month then local month_text = describe_compare_range( item.month_op, item.month_value, item.month_min_value, item.month_max_value, season_number_labels ) if month_text ~= '' then parts[#parts + 1] = month_text else parts[#parts + 1] = '月份' end end if item.check_day then local day_text = describe_compare_range( item.day_op, item.day_value, item.day_min_value, item.day_max_value, nil, '日' ) if day_text ~= '' then parts[#parts + 1] = day_text else parts[#parts + 1] = '日期' end end if item.check_weekday then local weekday_text = describe_compare_range( item.weekday_op, item.weekday_value, item.weekday_min_value, item.weekday_max_value, weekday_number_labels ) if weekday_text ~= '' then parts[#parts + 1] = weekday_text else parts[#parts + 1] = '星期' end end if item.check_year then local year_text = '' if common.trim(item.year_op) == 'Equal' and common.trim(item.year_value) ~= '' then year_text = '第' .. common.trim(item.year_value) .. '年' else year_text = describe_compare_range( item.year_op, item.year_value, item.year_min_value, item.year_max_value ) if year_text ~= '' then year_text = '年份' .. year_text end end if year_text ~= '' then parts[#parts + 1] = year_text else parts[#parts + 1] = '年份' end end if #parts > 0 then local text = table.concat(parts, '') if item.reverse then return '非' .. text end return text end return item.reverse and '日期条件不满足' or '日期条件' end return '特殊条件' end local function build_condition_text(variant) local condition_desc = clean_condition_desc(variant.condition_desc) local summary = variant.condition_summary local parts = {} if type(summary) == 'table' then for _, item in ipairs(summary) do local text = describe_condition_item(item) if text ~= '' then parts[#parts + 1] = text end end end local structured_text = table.concat(unique_texts(parts), ';') if condition_desc == '' then return structured_text end if structured_text == '' then return condition_desc end if should_use_structured_condition(condition_desc) then return structured_text end return condition_desc end local function build_variant_heading(variant) local parts = {} local apply_text = build_apply_text(variant) local condition_text = build_condition_text(variant) if apply_text ~= '' then parts[#parts + 1] = apply_text end if condition_text ~= '' then parts[#parts + 1] = condition_text end if #parts == 0 then return '默认' end return table.concat(parts, ' | ') end local function localize_location(value) local text = common.trim(value) if text == '' then return '' end local direct = location_labels[text] if direct then return direct end local festival_base = text:match('^(.-)_BeachFestival$') if festival_base then local base = localize_location(festival_base) if base ~= '' and base ~= festival_base then return base .. '(海滩节)' end end local location, actor = text:match('^(.-)_([A-Za-z][A-Za-z0-9]+)$') if location and actor and location_labels[location] then return location_labels[location] .. '(' .. actor .. ')' end return text:gsub('_', ' / ') end local function format_candidate_text(candidate) if type(candidate) ~= 'table' then return '' end local display_name = common.trim(candidate.display_name) local location = localize_location(candidate.location_hint) local template_name = common.trim(candidate.template) if display_name ~= '' and location ~= '' then return display_name .. '(' .. location .. ')' end if display_name ~= '' then return display_name end if location ~= '' and template_name ~= '' then return template_name .. '(' .. location .. ')' end return template_name end local function candidate_activity_text(candidate) if type(candidate) ~= 'table' then return '' end local display_name = common.trim(candidate.display_name) if display_name ~= '' then return display_name end return common.trim(candidate.template) end local function candidate_location_text(candidate) if type(candidate) ~= 'table' then return '' end return localize_location(candidate.location_hint) end local function format_slot_time(slot) local begin_time = common.trim(slot.begin_time) local end_time = common.trim(slot.end_time) if begin_time ~= '' and end_time ~= '' then return begin_time .. ' - ' .. end_time end return begin_time ~= '' and begin_time or end_time end local function format_slot_activity(slot) if type(slot) ~= 'table' then return '' end if common.trim(slot.kind) == 'mission' then local mission_display = common.trim(slot.mission_display) if mission_display ~= '' then return mission_display end local mission_title = common.trim(slot.mission_title) if mission_title ~= '' then return mission_title end return '任务' end local ranked_candidates, top_candidates = get_top_candidates(slot.action_candidates) if #top_candidates > 1 then local texts = {} for _, candidate in ipairs(top_candidates) do texts[#texts + 1] = candidate_activity_text(candidate) end return table.concat(unique_texts(texts), ' / ') end local primary_action = slot.primary_action if type(primary_action) ~= 'table' then if #ranked_candidates > 0 then return candidate_activity_text(ranked_candidates[1]) end return common.trim(slot.summary) end local display_name = common.trim(primary_action.display_name) if display_name ~= '' then return display_name end return common.trim(primary_action.template) end local function format_slot_location(slot) if type(slot) ~= 'table' then return '' end if common.trim(slot.kind) == 'mission' then return '' end local _, top_candidates = get_top_candidates(slot.action_candidates) if #top_candidates > 1 then local locations = {} for _, candidate in ipairs(top_candidates) do locations[#locations + 1] = candidate_location_text(candidate) end return table.concat(unique_texts(locations), ' / ') end local primary_action = slot.primary_action if type(primary_action) ~= 'table' then return '' end return localize_location(primary_action.location_hint) end local function format_slot_note(slot) if type(slot) ~= 'table' then return '' end if common.trim(slot.kind) == 'mission' then local notes = {} local mission_goal = common.trim(slot.mission_goal) local mission_title = common.trim(slot.mission_title) local mission_template = common.trim(slot.mission_template) if mission_goal ~= '' and not generic_mission_goals[mission_goal] then notes[#notes + 1] = mission_goal elseif mission_title ~= '' and mission_title ~= common.trim(slot.mission_display) then notes[#notes + 1] = mission_title end if mission_template ~= '' then notes[#notes + 1] = '模板:' .. mission_template end return table.concat(notes, ';') end local notes = {} local ranked_candidates, top_candidates = get_top_candidates(slot.action_candidates) if #top_candidates > 1 then local top_texts = {} for _, candidate in ipairs(top_candidates) do top_texts[#top_texts + 1] = format_candidate_text(candidate) end if #top_texts > 0 then notes[#notes + 1] = '并列候选:' .. table.concat(unique_texts(top_texts), ' / ') end elseif #ranked_candidates > 1 then local candidate_texts = {} for _, candidate in ipairs(ranked_candidates) do local text = format_candidate_text(candidate) if text ~= '' then candidate_texts[#candidate_texts + 1] = text end end if #candidate_texts > 0 then notes[#notes + 1] = '候选:' .. table.concat(candidate_texts, ' / ') end end local primary_action = slot.primary_action if type(primary_action) == 'table' then local template_name = common.trim(primary_action.template) local display_name = common.trim(primary_action.display_name) if template_name ~= '' and display_name == '' then notes[#notes + 1] = '模板:' .. template_name end end return table.concat(notes, ';') end local function render_variant_table(variant) local root = mw.html.create('table'):addClass('wikitable') local head = root:tag('tr') head:tag('th'):wikitext('时间') head:tag('th'):wikitext('行为') head:tag('th'):wikitext('地点') head:tag('th'):wikitext('备注') for _, slot in ipairs(variant.slots or {}) do local row = root:tag('tr') row:tag('td'):wikitext(format_slot_time(slot)) row:tag('td'):wikitext(format_slot_activity(slot)) row:tag('td'):wikitext(format_slot_location(slot)) row:tag('td'):wikitext(format_slot_note(slot)) end return tostring(root) end local function render_group(source, variants) local items = {} for _, variant in ipairs(variants) do if variant.source == source and type(variant.slots) == 'table' and #variant.slots > 0 then items[#items + 1] = variant end end if #items == 0 then return '' end local out = {} out[#out + 1] = '=== ' .. (source_labels[source] or source) .. ' ===' for _, variant in ipairs(items) do out[#out + 1] = '==== ' .. build_variant_heading(variant) .. ' ====' out[#out + 1] = render_variant_table(variant) end return table.concat(out, '\n') end local function filter_display_variants(variants) local out = {} if type(variants) ~= 'table' then return out end for _, variant in ipairs(variants) do if type(variant) == 'table' and type(variant.slots) == 'table' and #variant.slots > 0 then out[#out + 1] = variant end end return out end local function render_schedule_by_key(key) local record = find_record(key) if not record then return '' end local variants = filter_display_variants(merge_variants(record.variants)) if #variants == 0 then return '暂无日程数据。' end local out = {} local summary_counts = { regular = 0, special = 0, living_together = 0, } for _, variant in ipairs(variants) do local source = common.trim(variant.source) if summary_counts[source] ~= nil then summary_counts[source] = summary_counts[source] + 1 end end local summary = {} if summary_counts.regular > 0 then summary[#summary + 1] = '常规 ' .. tostring(summary_counts.regular) end if summary_counts.special > 0 then summary[#summary + 1] = '特殊 ' .. tostring(summary_counts.special) end if summary_counts.living_together > 0 then summary[#summary + 1] = '同居 ' .. tostring(summary_counts.living_together) end if #summary > 0 then out[#out + 1] = "''来源统计:" .. table.concat(summary, ',') .. "。同一条日程下拆开的星期规则已在展示层合并,多候选动作保留在备注列。''" end for _, source in ipairs({ 'regular', 'special', 'living_together' }) do local block = render_group(source, variants) if block ~= '' then out[#out + 1] = block end end return table.concat(out, '\n\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 return common.toText(record[field]) end function p.renderSchedule(frame) local key = common.getArg(frame, 1, '') return render_schedule_by_key(key) end return p
该页面嵌入的页面:
模板:Tl
(
查看源代码
)
模块:ArgsUtil
(
查看源代码
)
模块:Schedule/doc
(
查看源代码
)
模块:Template link
(
查看源代码
)
返回
模块:Schedule
。
查看“︁模块:Schedule”︁的源代码
来自星砂岛百科