维护提醒
BWIKI 全站将于 9 月 3 日(全天)进行维护,期间无法编辑任何页面或发布新的评论。
全站通知:
模块:Theater
刷
历
编
跳到导航
跳到搜索
local Helper = require('Module:Helper')
local NPC = require("Module:NPC")
local p = {}
local createMovieQuote
local createMovieQuotes
local moviesData = Helper.LazyLoad('Module:Theater/data/movies')
local concessionsData = Helper.LazyLoad('Module:Theater/data/concessions')
local concessionTastesData = Helper.LazyLoad('Module:Theater/data/concession tastes')
local moviesReactionsData = Helper.LazyLoad('Module:Theater/data/movies reactions')
local talkData = Helper.LazyLoad('Module:Talk/data')
local movieNames = {
["spring_movie_0"] = "勇敢的小树苗",
["summer_movie_0"] = "草原之王之旅:大电影",
["fall_movie_0"] = "神秘事迹",
["winter_movie_0"] = "冷星牧场的奇迹",
["spring_movie_1"] = "自然奇观:探索我们这充满活力的世界",
["summer_movie_1"] = "温布斯",
["fall_movie_1"] = "它在雨中嚎叫",
["winter_movie_1"] = "祖祖城特快列车"
}
local concessionNames = {
["0"] = "棉花糖",
["1"] = "茉莉花茶",
["2"] = "Joja 可乐",
["3"] = "酸味史莱姆",
["4"] = "个人披萨",
["5"] = "芝士玉米片",
["6"] = "鲑鱼汉堡",
["7"] = "冰淇淋三明治",
["8"] = "爆米花",
["9"] = "薯条",
["10"] = "巧克力爆米花",
["11"] = "黑甘草糖",
["12"] = "星形饼干",
["13"] = "大糖球",
["14"] = "盐渍花生",
["15"] = "鹰嘴豆泥小吃包",
["16"] = "羽衣甘蓝汁",
["17"] = "苹果脆片",
["18"] = "意式面包沙拉",
["19"] = "松露爆米花",
["20"] = "卡布奇诺慕斯蛋糕",
["21"] = "Joja 玉米",
["22"] = "星之果实冰糕",
["23"] = "糖冰棍"
}
local movieNamesEn = {
["spring_movie_0"] = "The Brave Little Sapling",
["summer_movie_0"] = "Journey Of The Prairie King: The Motion Picture",
["fall_movie_0"] = "Mysterium",
["winter_movie_0"] = "The Miracle At Coldstar Ranch",
["spring_movie_1"] = "Natural Wonders: Exploring Our Vibrant World",
["summer_movie_1"] = "Wumbus",
["fall_movie_1"] = "It Howls In The Rain",
["winter_movie_1"] = "The Zuzu City Express"
}
local concessionNamesEn = {
["0"] = "Cotton Candy",
["1"] = "Jasmine Tea",
["2"] = "Joja Cola",
["3"] = "Sour Slimes",
["4"] = "Personal Pizza",
["5"] = "Nachos",
["6"] = "Salmon Burger",
["7"] = "Ice Cream Sandwich",
["8"] = "Popcorn",
["9"] = "Fries",
["10"] = "Chocolate Popcorn",
["11"] = "Black Licorice",
["12"] = "Star Cookie",
["13"] = "Rock Candy",
["14"] = "Salted Peanuts",
["15"] = "Hummus Snack Pack",
["16"] = "Kale Smoothie",
["17"] = "Apple Slices",
["18"] = "Panzanella Salad",
["19"] = "Truffle Popcorn",
["20"] = "Cappuccino Mousse Cake",
["21"] = "Joja Corn",
["22"] = "Stardrop Sorbet",
["23"] = "Rock Candy"
}
local function getCharacterName(character)
if not character then return "" end
character = character:gsub("^%l", string.upper)
local chineseName = NPC.getChineseName(character)
if chineseName then return chineseName end
return character
end
local function getMovieTags(movieId)
for _, movie in ipairs(moviesData) do
if movie.Id == movieId then return movie.Tags or {} end
end
return {}
end
local function getConcessionTags(concessionId)
for _, concession in ipairs(concessionsData) do
if concession.Id == concessionId then
return concession.ItemTags or {}
end
end
return {}
end
local function calculateMoviePreference(npcName, movieId)
local movieTags = getMovieTags(movieId)
local npcReactions = nil
for _, npcData in ipairs(moviesReactionsData) do
if npcData.NPCName == npcName then
npcReactions = npcData.Reactions
break
end
end
if not npcReactions then return "like" end
for _, reaction in ipairs(npcReactions) do
if reaction.Tag == movieId then return reaction.Response end
end
for _, tag in ipairs(movieTags) do
for _, reaction in ipairs(npcReactions) do
if reaction.Tag == tag then return reaction.Response end
end
end
for _, reaction in ipairs(npcReactions) do
if reaction.Tag == "*" then return reaction.Response end
end
return "like"
end
local function calculateConcessionPreference(npcName, concessionId)
local concessionTags = getConcessionTags(concessionId)
local concessionName = nil
for _, concession in ipairs(concessionsData) do
if concession.Id == concessionId then
concessionName = concession.Name
break
end
end
local npcTastes = nil
local universalTastes = nil
for _, tasteData in ipairs(concessionTastesData) do
if tasteData.Name == npcName then
npcTastes = tasteData
elseif tasteData.Name == "*" then
universalTastes = tasteData
end
end
local function checkPreference(tastes, tags, concessionName)
if not tastes then return nil end
if concessionName then
for _, disliked in ipairs(tastes.DislikedTags or {}) do
if disliked == concessionName then
return "dislike"
end
end
for _, loved in ipairs(tastes.LovedTags or {}) do
if loved == concessionName then return "love" end
end
for _, liked in ipairs(tastes.LikedTags or {}) do
if liked == concessionName then return "like" end
end
end
for _, tag in ipairs(tags) do
for _, disliked in ipairs(tastes.DislikedTags or {}) do
if disliked == tag then return "dislike" end
end
for _, loved in ipairs(tastes.LovedTags or {}) do
if loved == tag then return "love" end
end
for _, liked in ipairs(tastes.LikedTags or {}) do
if liked == tag then return "like" end
end
end
return nil
end
local npcPreference = checkPreference(npcTastes, concessionTags,
concessionName)
if npcPreference then return npcPreference end
local universalPreference = checkPreference(universalTastes, concessionTags,
concessionName)
if universalPreference then return universalPreference end
return "like"
end
local function getMovieYearSeason(movieId)
for _, movie in ipairs(moviesData) do
if movie.Id == movieId then
local yearText = ""
local seasonText = ""
if movie.YearRemainder == 0 then
yearText = "第一年"
elseif movie.YearRemainder == 1 then
yearText = "第二年"
else
yearText = "第" .. (movie.YearRemainder + 1) .. "年"
end
if movie.Seasons then
local seasons = {}
for i, season in ipairs(movie.Seasons) do
local cleanSeason = tostring(season):gsub("^%s*(.-)%s*$",
"%1")
if cleanSeason then
table.insert(seasons,
'<br><div style="white-space: nowrap;">' ..
Helper.ExpandTemplate("Season",
{cleanSeason}) ..
'</div>')
end
end
seasonText = table.concat(seasons, "、")
end
return yearText .. seasonText
end
end
return ""
end
function p.getNPCMoviePreferences(frame)
local npcName = frame.args[1] or frame.args.npc
if not npcName then return "<!-- 错误:请提供NPC名称 -->" end
local displayName = npcName
local englishName = npcName
if NPC.getEnglishName(npcName) then
englishName = NPC.getEnglishName(npcName)
else
displayName = getCharacterName(npcName)
end
local loved = {}
local liked = {}
local disliked = {}
for _, movie in ipairs(moviesData) do
local preference = calculateMoviePreference(englishName, movie.Id)
local movieName = movieNames[movie.Id] or movie.Id
local yearSeason = getMovieYearSeason(movie.Id)
local movieDisplayName = movieName .. "(" .. yearSeason .. ")"
if preference == "love" then
table.insert(loved, movieDisplayName)
elseif preference == "like" then
table.insert(liked, movieDisplayName)
elseif preference == "dislike" then
table.insert(disliked, movieDisplayName)
end
end
local result = "=== " .. displayName .. "的电影喜好 ===\n"
if #loved > 0 then
result = result .. "'''最爱:'''" .. table.concat(loved, "、") ..
"\n\n"
end
if #liked > 0 then
result = result .. "'''喜欢:'''" .. table.concat(liked, "、") ..
"\n\n"
end
if #disliked > 0 then
result =
result .. "'''不喜欢:'''" .. table.concat(disliked, "、") ..
"\n\n"
end
return result
end
function p.getNPCConcessionPreferences(frame)
local npcName = frame.args[1] or frame.args.npc
if not npcName then return "<!-- 错误:请提供NPC名称 -->" end
local displayName = npcName
local englishName = npcName
if NPC.getEnglishName(npcName) then
englishName = NPC.getEnglishName(npcName)
else
displayName = getCharacterName(npcName)
end
local loved = {}
local liked = {}
local disliked = {}
for _, concession in ipairs(concessionsData) do
local preference = calculateConcessionPreference(englishName,
concession.Id)
local concessionName = concessionNames[concession.Id] or concession.Name
if preference == "love" then
table.insert(loved, concessionName)
elseif preference == "like" then
table.insert(liked, concessionName)
elseif preference == "dislike" then
table.insert(disliked, concessionName)
end
end
local result = "=== " .. displayName .. "的零食喜好 ===\n"
if #loved > 0 then
result = result .. "'''最爱:'''" .. table.concat(loved, "、") ..
"\n\n"
end
if #liked > 0 then
result = result .. "'''喜欢:'''" .. table.concat(liked, "、") ..
"\n\n"
end
if #disliked > 0 then
result =
result .. "'''不喜欢:'''" .. table.concat(disliked, "、") ..
"\n\n"
end
return result
end
function p.getMovieNPCPreferences(frame)
local movieId = frame.args[1] or frame.args.movie
if not movieId then return "<!-- 错误:请提供电影ID -->" end
local movieName = movieNames[movieId] or movieId
local yearSeason = getMovieYearSeason(movieId)
local loved = {}
local liked = {}
local disliked = {}
local allNPCs = {}
for _, npcData in ipairs(moviesReactionsData) do
table.insert(allNPCs, npcData.NPCName)
end
for _, npcName in ipairs(allNPCs) do
local preference = calculateMoviePreference(npcName, movieId)
if preference == "love" then
table.insert(loved, npcName)
elseif preference == "like" then
table.insert(liked, npcName)
elseif preference == "dislike" then
table.insert(disliked, npcName)
end
end
local result = "=== 《" .. movieName .. "》(" .. yearSeason ..
")的观众喜好 ===\n"
if #loved > 0 then
result = result .. "'''最爱:'''" .. table.concat(loved, "、") ..
"\n\n"
end
if #liked > 0 then
result = result .. "'''喜欢:'''" .. table.concat(liked, "、") ..
"\n\n"
end
if #disliked > 0 then
result =
result .. "'''不喜欢:'''" .. table.concat(disliked, "、") ..
"\n\n"
end
return result
end
function p.getConcessionNPCPreferences(frame)
local concessionId = frame.args[1] or frame.args.concession
if not concessionId then return "<!-- 错误:请提供零食ID -->" end
local concessionName = concessionNames[concessionId] or concessionId
local loved = {}
local liked = {}
local disliked = {}
local allNPCs = {}
for _, tasteData in ipairs(concessionTastesData) do
if tasteData.Name ~= "*" then
table.insert(allNPCs, tasteData.Name)
end
end
for _, npcName in ipairs(allNPCs) do
local preference = calculateConcessionPreference(npcName, concessionId)
if preference == "love" then
table.insert(loved, npcName)
elseif preference == "like" then
table.insert(liked, npcName)
elseif preference == "dislike" then
table.insert(disliked, npcName)
end
end
local result = "=== " .. concessionName .. "的受欢迎程度 ===\n"
if #loved > 0 then
result = result .. "'''最爱:'''" .. table.concat(loved, "、") ..
"\n\n"
end
if #liked > 0 then
result = result .. "'''喜欢:'''" .. table.concat(liked, "、") ..
"\n\n"
end
if #disliked > 0 then
result =
result .. "'''不喜欢:'''" .. table.concat(disliked, "、") ..
"\n\n"
end
return result
end
function p.getConcessionPrice(frame)
local concessionId = frame.args[1] or frame.args.concession
if not concessionId then return "<!-- 错误:请提供零食ID -->" end
for _, concession in ipairs(concessionsData) do
if concession.Id == concessionId then
local concessionName = concessionNames[concessionId] or
concession.Name
return concessionName .. "的价格:" ..
Helper.ExpandTemplate("price", {concession.Price})
end
end
return "<!-- 错误:未找到零食ID " .. concessionId .. " -->"
end
function p.getMovieCranePrizes(frame)
local movieId = frame.args[1] or frame.args.movie
if not movieId then return "<!-- 错误:请提供电影ID -->" end
local movieName = movieNames[movieId] or movieId
local yearSeason = getMovieYearSeason(movieId)
for _, movie in ipairs(moviesData) do
if movie.Id == movieId then
local result = "=== 《" .. movieName .. "》(" .. yearSeason ..
")上映期间的娃娃机特殊物品 ===\n"
if movie.CranePrizes and #movie.CranePrizes > 0 then
for _, prize in ipairs(movie.CranePrizes) do
local rarity = ""
if prize.Rarity == 1 then
rarity = "(普通)"
elseif prize.Rarity == 2 then
rarity = "(稀有)"
elseif prize.Rarity == 3 then
rarity = "(豪华)"
end
local itemId = prize.ItemId
if itemId and itemId:match("%(F%)(%d+)") then
local furnitureId = itemId:match("%(F%)(%d+)")
result = result .. "* " ..
Helper.ExpandTemplate("Name", {furnitureId}) ..
rarity .. "\n"
else
result =
result .. "* " .. (prize.Id or "未知物品") ..
rarity .. "\n"
end
end
else
result = result ..
"该电影上映期间没有特殊物品。\n"
end
return result
end
end
return "<!-- 错误:未找到电影ID " .. movieId .. " -->"
end
local function extractScriptDialogue(script)
if not script then return nil end
local messageDialogue = script:match('/message%s+"([^"]+)"')
if messageDialogue then return messageDialogue end
local complexMessage = script:match('/emote%s+[^/]+/message%s+"([^"]+)"')
if complexMessage then return complexMessage end
return nil
end
local function getMovieDialogueTexts(translationKey, script)
local textDialogues = {}
local scriptDialogues = {}
local processedKeys = {}
if translationKey and translationKey ~= "" then
if talkData then
local key = translationKey:match(
"%[LocalizedText Strings\\MovieReactions:(.+)%]")
if key and talkData.MovieReactions then
processedKeys[key] = true
if talkData.MovieReactions[key] then
table.insert(textDialogues, talkData.MovieReactions[key])
end
else
table.insert(textDialogues, translationKey)
end
else
table.insert(textDialogues, translationKey)
end
end
if script then
local scriptDialogue = extractScriptDialogue(script)
if scriptDialogue then
if scriptDialogue:match("%[LocalizedText") then
local scriptKey = scriptDialogue:match(
"%[LocalizedText Strings\\MovieReactions:(.+)%]")
if scriptKey and not processedKeys[scriptKey] then
local scriptTexts = getMovieDialogueTexts(scriptDialogue,
nil)
for _, text in ipairs(scriptTexts.textDialogues or {}) do
table.insert(scriptDialogues, text)
end
end
else
table.insert(scriptDialogues, scriptDialogue)
end
end
end
return {textDialogues = textDialogues, scriptDialogues = scriptDialogues}
end
local function cleanMovieText(text)
if not text or type(text) ~= "string" then return text, nil end
local emotion = nil
emotion = text:match("%$([hslua])$")
if not emotion then
emotion = text:match("%$(%d+)$")
if emotion then
local num = tonumber(emotion)
if not num or num < 0 or num > 15 then emotion = nil end
end
end
text = text:gsub("%$[hslua]$", "")
text = text:gsub("%$%d+$", "")
text = text:gsub("%$%{([^%^}]+)%^([^}]+)%}", "%1/%2")
text = text:gsub("\\\"", "\"")
text = text:gsub("\\n", "\n")
text = text:gsub("@", '<span class="player-name">玩家名</span>')
local has0 = text:find("{0}") ~= nil
local has2 = text:find("{2}") ~= nil
if has0 and has2 then
text = text:gsub("{0}", '<span class="player-name">电影名称</span>')
text = text:gsub("{2}", '<span class="player-name">人物名称</span>')
elseif has0 then
text = text:gsub("{0}", '<span class="player-name">_____</span>')
elseif has2 then
text = text:gsub("{2}", '<span class="player-name">_____</span>')
end
text = text:gsub("%%noturn",
'<span class="trigger-chance">(不转身)</span>')
text = text:gsub("%$[hbslaue]", "")
text = text:gsub("%$%d+", "")
text = text:gsub("##", "\n")
text = text:gsub("%s*%[%s*%d+%s*%]",
'<span class="refuse-item">(给予物品)</span>')
if text:match("^[^。!?]*在[^。!?]*。?%s*$") then
text = '<span class="action-description">' .. text .. '</span>'
end
if emotion then
if emotion == "h" then
emotion = "1"
elseif emotion == "s" then
emotion = "2"
elseif emotion == "u" then
emotion = "3"
elseif emotion == "l" then
emotion = "4"
elseif emotion == "a" then
emotion = "5"
end
end
return text, emotion
end
local function processMovieGenderDialogue(text, characterName, isFromScript)
if not text or type(text) ~= "string" then return text end
local hasInlineGender = text:find("%$%{[^%^}]+%^[^}]+%}%$")
if hasInlineGender then
local maleText = text:gsub("%$%{([^%^}]+)%^[^}]+%}%$", "%1")
local femaleText = text:gsub("%$%{[^%^}]+%^([^}]+)%}%$", "%1")
local maleResult = createMovieQuote(maleText ..
'<span class="trigger-chance">(男)</span>',
characterName, isFromScript)
local femaleResult = createMovieQuote(femaleText ..
'<span class="trigger-chance">(女)</span>',
characterName, isFromScript)
return maleResult .. "\n" .. femaleResult
end
if not text:find("%^") then
return createMovieQuote(text, characterName, isFromScript)
end
local caretPos = text:find("%^")
local beforeCaret = text:sub(1, caretPos - 1)
local afterCaret = text:sub(caretPos + 1)
local maleText = beforeCaret:match("^%s*(.-)%s*$") or ""
local femaleText = afterCaret:match("^%s*(.-)%s*$") or ""
local maleResult = createMovieQuote(maleText ..
'<span class="trigger-chance">(男)</span>',
characterName, isFromScript)
local femaleResult = createMovieQuote(femaleText ..
'<span class="trigger-chance">(女)</span>',
characterName, isFromScript)
return maleResult .. "\n" .. femaleResult
end
-- 处理单个对话片段(不包含分隔符)
local createMovieQuoteSingle = function(text, characterName, isFromScript)
if not text then return "" end
local cleanedText, emotion = cleanMovieText(text)
if isFromScript then
return Helper.ExpandTemplate("Say", {"voiceover", cleanedText})
end
local chineseName = getCharacterName(characterName)
local portrait = characterName
if portrait then portrait = portrait:lower() end
if not emotion and characterName then emotion = "0" end
if emotion and portrait then
return Helper.ExpandTemplate("Say", {
"left", chineseName, cleanedText, emotion, portrait
})
else
return Helper.ExpandTemplate("Say", {"left", chineseName, cleanedText})
end
end
-- 处理包含分隔符的电影对话文本,分割为独立对话
local function processMovieDialogueWithSeparators(text, characterName, isFromScript)
if not text or type(text) ~= "string" then
return ""
end
-- 分割对话:#$b# 和 #$e# 都作为分隔符
local parts = {}
local currentPart = ""
local i = 1
while i <= #text do
if text:sub(i, i + 3) == "#$b#" then
if currentPart ~= "" then
table.insert(parts, currentPart)
currentPart = ""
end
i = i + 4
elseif text:sub(i, i + 3) == "#$e#" then
if currentPart ~= "" then
table.insert(parts, currentPart)
currentPart = ""
end
i = i + 4
else
currentPart = currentPart .. text:sub(i, i)
i = i + 1
end
end
-- 添加最后一部分
if currentPart ~= "" then
table.insert(parts, currentPart)
end
-- 如果没有分隔符,直接处理整个文本
if #parts <= 1 then
return createMovieQuoteSingle(text, characterName, isFromScript)
end
-- 处理每个独立的对话片段
local results = {}
for _, part in ipairs(parts) do
local trimmed = part:match("^%s*(.-)%s*$")
if trimmed and trimmed ~= "" then
-- 检查这个片段是否包含性别分支
if trimmed:find("%^") or trimmed:find("%$%{[^%^}]+%^[^}]+%}%$") then
-- 有性别分支,调用性别处理函数
table.insert(results, processMovieGenderDialogue(trimmed, characterName, isFromScript))
else
-- 没有性别分支,直接处理
table.insert(results, createMovieQuoteSingle(trimmed, characterName, isFromScript))
end
end
end
return table.concat(results, "\n")
end
createMovieQuote = function(text, characterName, isFromScript)
if not text then return "" end
-- 检查是否包含分隔符
if text:find("#%$[be]#") then
return processMovieDialogueWithSeparators(text, characterName, isFromScript)
else
return createMovieQuoteSingle(text, characterName, isFromScript)
end
end
createMovieQuotes = function(dialogues, characterName, isFromScript)
if not dialogues or #dialogues == 0 then return "" end
local result = {}
for _, dialogue in ipairs(dialogues) do
if dialogue:find("%^") or dialogue:find("%$%{[^%^}]+%^[^}]+%}%$") then
local quote = processMovieGenderDialogue(dialogue, characterName,
isFromScript)
if quote and quote ~= "" then table.insert(result, quote) end
else
local quote =
createMovieQuote(dialogue, characterName, isFromScript)
if quote and quote ~= "" then table.insert(result, quote) end
end
end
return table.concat(result, "\n")
end
local function processDialogueCategory(title, dialogues, englishName)
if not dialogues then return "" end
local dialogueContent = {}
if dialogues.BeforeMovie then
local result = getMovieDialogueTexts(dialogues.BeforeMovie.Text,
dialogues.BeforeMovie.Script)
local allQuotes = {}
if #result.textDialogues > 0 then
table.insert(allQuotes, createMovieQuotes(result.textDialogues,
englishName, false))
end
if #result.scriptDialogues > 0 then
table.insert(allQuotes, createMovieQuotes(result.scriptDialogues,
englishName, true))
end
if #allQuotes > 0 then
table.insert(dialogueContent, table.concat(allQuotes, "\n"))
end
end
if dialogues.DuringMovie then
local result = getMovieDialogueTexts(dialogues.DuringMovie.Text,
dialogues.DuringMovie.Script)
local allQuotes = {}
if #result.textDialogues > 0 then
table.insert(allQuotes, createMovieQuotes(result.textDialogues,
englishName, false))
end
if #result.scriptDialogues > 0 then
table.insert(allQuotes, createMovieQuotes(result.scriptDialogues,
englishName, true))
end
if #allQuotes > 0 then
table.insert(dialogueContent, table.concat(allQuotes, "\n"))
end
end
if dialogues.AfterMovie then
local result = getMovieDialogueTexts(dialogues.AfterMovie.Text,
dialogues.AfterMovie.Script)
local allQuotes = {}
if #result.textDialogues > 0 then
table.insert(allQuotes, createMovieQuotes(result.textDialogues,
englishName, false))
end
if #result.scriptDialogues > 0 then
table.insert(allQuotes, createMovieQuotes(result.scriptDialogues,
englishName, true))
end
if #allQuotes > 0 then
table.insert(dialogueContent, table.concat(allQuotes, "\n"))
end
end
if #dialogueContent > 0 then
local eventLabelContent =
'<div class="event-label show" style="display: block;">\n' ..
table.concat(dialogueContent, "\n") .. '\n</div>'
return Helper.ExpandTemplate("Collapse",
{title, content = eventLabelContent})
end
return ""
end
function p.getNPCMovieDialogue(frame)
local npcName = frame.args[1] or frame.args.npc
if not npcName then return "<!-- 错误:请提供NPC名称 -->" end
local displayName = npcName
local englishName = npcName
if NPC.getEnglishName(npcName) then
englishName = NPC.getEnglishName(npcName)
else
displayName = getCharacterName(npcName)
end
-- 收集电影邀约对话
local inviteDialogues = {}
-- 1. 从NPC个人数据中获取MovieInvitation
if talkData and talkData[englishName] and talkData[englishName].MovieInvitation then
table.insert(inviteDialogues, {
type = "regular",
dialogue = talkData[englishName].MovieInvitation
})
end
-- 2. 从Strings/Characters获取婚后对话
if talkData and talkData["Strings/Characters"] then
local stringsData = talkData["Strings/Characters"]
local spouseKey = "MovieInvite_Spouse_" .. englishName
if stringsData[spouseKey] then
table.insert(inviteDialogues, {
type = "spouse",
dialogue = stringsData[spouseKey]
})
end
-- 3. 获取通用邀约对话(如果没有个人对话且没有婚后对话)
local hasRegularDialogue = false
for _, invite in ipairs(inviteDialogues) do
if invite.type == "regular" then
hasRegularDialogue = true
break
end
end
if not hasRegularDialogue then
-- 定义 child 和 rude NPC 列表
local childNPCs = {"Vincent", "Jas"}
local rudeNPCs = {"Abigail", "Alex", "Clint", "George", "Haley", "Pam", "Sebastian", "Shane", "Wizard"}
-- 检查是否为 child
local isChild = false
for _, child in ipairs(childNPCs) do
if englishName == child then
isChild = true
break
end
end
-- 检查是否为 rude
local isRude = false
for _, rude in ipairs(rudeNPCs) do
if englishName == rude then
isRude = true
break
end
end
-- 按优先级查找通用对话
local fallbackKeys = {
"MovieInvite_Invited_" .. englishName
}
-- 根据 NPC 类型添加相应的回退对话
if isChild then
table.insert(fallbackKeys, "MovieInvite_Invited_Child")
elseif isRude then
table.insert(fallbackKeys, "MovieInvite_Invited_Rude")
else
table.insert(fallbackKeys, "MovieInvite_Invited")
end
for _, key in ipairs(fallbackKeys) do
if stringsData[key] then
table.insert(inviteDialogues, {
type = "regular",
dialogue = stringsData[key]
})
break
end
end
end
end
local result = ""
-- 处理邀约对话
if #inviteDialogues > 0 then
local inviteContent = {}
local regularDialogues = {}
local spouseDialogues = {}
for _, invite in ipairs(inviteDialogues) do
if invite.type == "spouse" then
table.insert(spouseDialogues, invite.dialogue)
else
table.insert(regularDialogues, invite.dialogue)
end
end
-- 先输出常规对话
if #regularDialogues > 0 then
for _, dialogue in ipairs(regularDialogues) do
local quote = createMovieQuote(dialogue, englishName, false)
if quote and quote ~= "" then
table.insert(inviteContent, quote)
end
end
end
-- 再输出婚后对话
if #spouseDialogues > 0 then
table.insert(inviteContent, "'''婚后'''")
for _, dialogue in ipairs(spouseDialogues) do
local quote = createMovieQuote(dialogue, englishName, false)
if quote and quote ~= "" then
table.insert(inviteContent, quote)
end
end
end
if #inviteContent > 0 then
local eventLabelContent =
'<div class="event-label show" style="display: block;">\n' ..
table.concat(inviteContent, "\n") .. '\n</div>'
result = result .. Helper.ExpandTemplate("Collapse",
{"发起邀约", content = eventLabelContent}) .. "\n"
end
end
local npcReactions = nil
for _, npcData in ipairs(moviesReactionsData) do
if npcData.NPCName == englishName then
npcReactions = npcData.Reactions
break
end
end
if not npcReactions then
return result .. "<!-- 错误:未找到NPC " .. displayName ..
" 的电影反应数据 -->"
end
local movieDialogues = {}
local reactionDialogues = {}
local genreDialogues = {}
local generalDialogues = {}
for _, reaction in ipairs(npcReactions) do
if reaction.SpecialResponses then
local tag = reaction.Tag
local movieName = movieNames[tag]
if movieName then
movieDialogues[movieName] = reaction.SpecialResponses
elseif tag == "*" then
generalDialogues["通用"] = reaction.SpecialResponses
elseif tag == "love" or tag == "like" or tag == "dislike" or tag ==
"seen_love" or tag == "seen_like" or tag == "seen_dislike" then
local categoryTitle = ""
if tag == "love" or tag == "seen_love" then
categoryTitle = "最爱的电影"
elseif tag == "dislike" or tag == "seen_dislike" then
categoryTitle = "不喜欢的电影"
elseif tag == "like" or tag == "seen_like" then
categoryTitle = "喜欢的电影"
end
if tag:match("^seen_") then
categoryTitle = categoryTitle .. "(已看过)"
end
reactionDialogues[categoryTitle] = reaction.SpecialResponses
else
local categoryTitle = ""
if tag == "family" then
categoryTitle = "家庭类电影"
elseif tag == "comedy" then
categoryTitle = "喜剧类电影"
elseif tag == "horror" then
categoryTitle = "恐怖类电影"
elseif tag == "action" then
categoryTitle = "动作类电影"
elseif tag == "sci-fi" then
categoryTitle = "科幻类电影"
elseif tag == "classic" then
categoryTitle = "经典类电影"
elseif tag == "romance" then
categoryTitle = "浪漫类电影"
elseif tag == "documentary" then
categoryTitle = "纪录片类电影"
elseif tag == "art" then
categoryTitle = "艺术类电影"
else
categoryTitle = tag .. "类电影"
end
genreDialogues[categoryTitle] = reaction.SpecialResponses
end
end
end
local outputTemplates = {}
for movieName, dialogues in pairs(movieDialogues) do
local collapseTemplate = processDialogueCategory(movieName, dialogues,
englishName)
if collapseTemplate ~= "" then
table.insert(outputTemplates, collapseTemplate)
end
end
for categoryTitle, dialogues in pairs(genreDialogues) do
local collapseTemplate = processDialogueCategory(categoryTitle,
dialogues, englishName)
if collapseTemplate ~= "" then
table.insert(outputTemplates, collapseTemplate)
end
end
local reactionOrder = {
"最爱的电影", "最爱的电影(已看过)", "喜欢的电影",
"喜欢的电影(已看过)", "不喜欢的电影",
"不喜欢的电影(已看过)"
}
for _, categoryTitle in ipairs(reactionOrder) do
if reactionDialogues[categoryTitle] then
local collapseTemplate = processDialogueCategory(categoryTitle,
reactionDialogues[categoryTitle],
englishName)
if collapseTemplate ~= "" then
table.insert(outputTemplates, collapseTemplate)
end
end
end
for dialogueType, dialogues in pairs(generalDialogues) do
local collapseTemplate = processDialogueCategory("通用及特殊",
dialogues, englishName)
if collapseTemplate ~= "" then
table.insert(outputTemplates, collapseTemplate)
end
end
if #outputTemplates > 0 then
result = result .. "\n" .. table.concat(outputTemplates, "\n\n")
end
return result
end
function p.getAllMoviesInfo(frame)
local result = "=== 所有电影信息 ===\n"
for _, movie in ipairs(moviesData) do
local movieName = movieNames[movie.Id] or movie.Id
local yearSeason = getMovieYearSeason(movie.Id)
result = result .. "\n==== " .. movieName .. "(" .. yearSeason ..
") ====\n"
result = result .. "* '''ID:'''" .. movie.Id .. "\n"
result = result .. "* '''季节:'''" ..
table.concat(movie.Seasons or {}, "、") .. "\n"
if movie.YearModulus and movie.YearRemainder then
local yearDesc = ""
if movie.YearModulus == 2 then
if movie.YearRemainder == 0 then
yearDesc = "第一年"
else
yearDesc = "第二年"
end
else
yearDesc = "每" .. movie.YearModulus .. "年,余数" ..
movie.YearRemainder
end
result = result .. "* '''年份:'''" .. yearDesc .. "\n"
end
if movie.Tags and #movie.Tags > 0 then
local tagNames = {}
for _, tag in ipairs(movie.Tags) do
local tagName = tag
if tag == "family" then
tagName = "家庭"
elseif tag == "comedy" then
tagName = "喜剧"
elseif tag == "horror" then
tagName = "恐怖"
elseif tag == "action" then
tagName = "动作"
elseif tag == "sci-fi" then
tagName = "科幻"
elseif tag == "classic" then
tagName = "经典"
elseif tag == "romance" then
tagName = "浪漫"
elseif tag == "documentary" then
tagName = "纪录片"
elseif tag == "art" then
tagName = "艺术"
end
table.insert(tagNames, tagName)
end
result = result .. "* '''类型:'''" ..
table.concat(tagNames, "、") .. "\n"
end
if movie.CranePrizes and #movie.CranePrizes > 0 then
result = result .. "* '''娃娃机特殊物品:'''" ..
#movie.CranePrizes .. "种\n"
end
end
return result
end
function p.getNPCCinemaTable(frame)
local npcName = frame.args[1] or frame.args.npc
if not npcName then return "<!-- 错误:请提供NPC名称 -->" end
local displayName = npcName
local englishName = npcName
if NPC.getEnglishName(npcName) then
englishName = NPC.getEnglishName(npcName)
else
displayName = getCharacterName(npcName)
end
local moviePreferences = {loved = {}, liked = {}, disliked = {}}
for _, movie in ipairs(moviesData) do
local preference = calculateMoviePreference(englishName, movie.Id)
local movieName = movieNames[movie.Id] or movie.Id
local yearSeason = getMovieYearSeason(movie.Id)
local movieDisplayName = movieName .. "(" .. yearSeason .. ")"
local movieEnglishName = movieNamesEn[movie.Id]:gsub(':', '')
local movieImageName = ""
if movieEnglishName then
movieImageName = "'" .. movieEnglishName .. "'.png"
end
local movieEntry = {
image = movieImageName,
name = movieName,
season = yearSeason,
yearRemainder = movie.YearRemainder or 0,
seasons = movie.Seasons or {}
}
if preference == "love" then
table.insert(moviePreferences.loved, movieEntry)
elseif preference == "like" then
table.insert(moviePreferences.liked, movieEntry)
elseif preference == "dislike" then
table.insert(moviePreferences.disliked, movieEntry)
end
end
local function sortMovies(movieList)
table.sort(movieList, function(a, b)
if a.yearRemainder ~= b.yearRemainder then
return a.yearRemainder < b.yearRemainder
end
local seasonOrder = {
spring = 0,
summer = 1,
fall = 2,
winter = 3,
Spring = 0,
Summer = 1,
Fall = 2,
Winter = 3
}
local aMinSeason = 4
local bMinSeason = 4
for _, season in ipairs(a.seasons) do
local seasonValue = seasonOrder[season]
if seasonValue and seasonValue < aMinSeason then
aMinSeason = seasonValue
end
end
for _, season in ipairs(b.seasons) do
local seasonValue = seasonOrder[season]
if seasonValue and seasonValue < bMinSeason then
bMinSeason = seasonValue
end
end
if aMinSeason == bMinSeason then return a.name < b.name end
return aMinSeason < bMinSeason
end)
end
sortMovies(moviePreferences.loved)
sortMovies(moviePreferences.liked)
sortMovies(moviePreferences.disliked)
local concessionPreferences = {loved = {}, liked = {}, disliked = {}}
for _, concession in ipairs(concessionsData) do
local preference = calculateConcessionPreference(englishName,
concession.Id)
local concessionName = concessionNames[concession.Id] or concession.Name
local concessionImageName = concession.Name .. ".png"
if concession.Name == "Joja Cola" then
concessionImageName = "Joja Cola (large).png"
end
local concessionEntry = {
image = concessionImageName,
name = concessionName
}
if preference == "love" then
table.insert(concessionPreferences.loved, concessionEntry)
elseif preference == "like" then
table.insert(concessionPreferences.liked, concessionEntry)
elseif preference == "dislike" then
table.insert(concessionPreferences.disliked, concessionEntry)
end
end
local movieTableHTML =
'<table class="wikitable" style="margin: 0; margin-top: 1em;">\n'
if #moviePreferences.loved > 0 then
movieTableHTML = movieTableHTML ..
'<tr><th colspan="2">最爱 <span style="font-size:smaller;">+200</span></th></tr>\n'
for _, movie in ipairs(moviePreferences.loved) do
movieTableHTML =
movieTableHTML .. '<tr><td>[[File:' .. movie.image ..
'|24px|link=]] ' .. movie.name ..
'</td><td style="text-align: center; padding: 2px 16px;">' ..
movie.season .. '</td></tr>\n'
end
end
if #moviePreferences.liked > 0 then
movieTableHTML = movieTableHTML ..
'<tr><th colspan="2">喜欢 <span style="font-size:smaller;">+100</span></th></tr>\n'
for _, movie in ipairs(moviePreferences.liked) do
movieTableHTML =
movieTableHTML .. '<tr><td>[[File:' .. movie.image ..
'|24px|link=]] ' .. movie.name ..
'</td><td style="text-align: center; padding: 2px 16px;">' ..
movie.season .. '</td></tr>\n'
end
end
if #moviePreferences.disliked > 0 then
movieTableHTML = movieTableHTML ..
'<tr><th colspan="2">不喜欢<span style="font-size:smaller;"></span></th></tr>\n'
for _, movie in ipairs(moviePreferences.disliked) do
movieTableHTML =
movieTableHTML .. '<tr><td>[[File:' .. movie.image ..
'|24px|link=]] ' .. movie.name ..
'</td><td style="text-align: center; padding: 2px 16px;">' ..
movie.season .. '</td></tr>\n'
end
end
movieTableHTML = movieTableHTML .. '</table>'
local lovedItems = {}
local likedItems = {}
local dislikedItems = {}
for i, concession in ipairs(concessionPreferences.loved) do
table.insert(lovedItems, '[[File:' .. concession.image ..
'|24px|link=]] ' .. concession.name .. '')
end
for i, concession in ipairs(concessionPreferences.liked) do
table.insert(likedItems, '[[File:' .. concession.image ..
'|24px|link=]] ' .. concession.name .. '')
end
for i, concession in ipairs(concessionPreferences.disliked) do
table.insert(dislikedItems, '[[File:' .. concession.image ..
'|24px|link=]] ' .. concession.name .. '')
end
local concessionTableHTML =
'<table class="wikitable" style="margin: 0; margin-top: 1em;">\n'
local likedCount = #likedItems
local dislikedCount = #dislikedItems
local leftBottomTitle, leftBottomItems, leftBottomIcon, leftBottomScore
local rightTitle, rightItems, rightIcon, rightScore
if likedCount <= dislikedCount then
leftBottomTitle = "喜欢"
leftBottomItems = likedItems
leftBottomIcon = "ConcessionLike.png"
leftBottomScore = "+25"
rightTitle = "不喜欢"
rightItems = dislikedItems
rightIcon = "ConcessionDislike.png"
rightScore = ""
else
leftBottomTitle = "不喜欢"
leftBottomItems = dislikedItems
leftBottomIcon = "ConcessionDislike.png"
leftBottomScore = ""
rightTitle = "喜欢"
rightItems = likedItems
rightIcon = "ConcessionLike.png"
rightScore = "+25"
end
concessionTableHTML = concessionTableHTML .. '<tr>\n'
concessionTableHTML = concessionTableHTML ..
'<th>[[File:ConcessionLove.png|24px|link=]] 最爱 <span style="font-size:smaller;">+50</span></th>\n'
concessionTableHTML = concessionTableHTML ..
'<th rowspan="1" style="vertical-align: top;">[[File:' ..
rightIcon .. '|24px|link=]] ' .. rightTitle ..
' <span style="font-size:smaller;">' .. rightScore ..
'</span></th>\n'
concessionTableHTML = concessionTableHTML .. '</tr>\n'
concessionTableHTML = concessionTableHTML ..
'<tr style="vertical-align: top;">\n'
concessionTableHTML = concessionTableHTML ..
'<td style="padding: 4px 6px;">' ..
table.concat(lovedItems, '<br>') .. '</td>\n'
concessionTableHTML = concessionTableHTML ..
'<td rowspan="3" style="padding: 4px 6px; vertical-align: top;">' ..
table.concat(rightItems, '<br>') .. '</td>\n'
concessionTableHTML = concessionTableHTML .. '</tr>\n'
concessionTableHTML = concessionTableHTML .. '<tr>\n'
concessionTableHTML = concessionTableHTML ..
'<th style="height: 30px;">[[File:' ..
leftBottomIcon .. '|24px|link=]] ' ..
leftBottomTitle ..
' <span style="font-size:smaller;">' ..
leftBottomScore .. '</span></th>\n'
concessionTableHTML = concessionTableHTML .. '</tr>\n'
concessionTableHTML = concessionTableHTML ..
'<tr style="vertical-align: top;">\n'
concessionTableHTML = concessionTableHTML ..
'<td style="padding: 4px 6px;">' ..
table.concat(leftBottomItems, '<br>') .. '</td>\n'
concessionTableHTML = concessionTableHTML .. '</tr>\n'
concessionTableHTML = concessionTableHTML .. '</table>'
local cinemaTableHTML =
'<div style="display: flex; flex-wrap: wrap; gap: 16px;">\n'
cinemaTableHTML = cinemaTableHTML .. '<div>\n' .. movieTableHTML ..
'\n</div>\n'
cinemaTableHTML = cinemaTableHTML .. '<div>\n' .. concessionTableHTML ..
'\n</div>\n'
cinemaTableHTML = cinemaTableHTML .. '</div>'
return cinemaTableHTML
end
return p