维护提醒
BWIKI 全站将于 9 月 3 日(全天)进行维护,期间无法编辑任何页面或发布新的评论。
全站通知:
模块:Dialogue
刷
历
编
跳到导航
跳到搜索
local p = {}
local Helper = require("Module:Helper")
local NPC = require("Module:NPC")
local ItemNames = require("Module:ItemNames")
local AcceptGiftData = Helper.LazyLoad("Module:Dialogue/data/accept gift")
local AcceptBirthdayGiftData = Helper.LazyLoad("Module:Dialogue/data/accept birthday gift")
local GiftTastesData = Helper.LazyLoad("Module:GiftTastesNPC/data")
local TagData = Helper.LazyLoad("Module:Tag/data")
local attitudeMapping = {
["Negative"] = "态度为不喜欢或讨厌时",
["Positive"] = "态度为最爱或喜欢时",
["Neutral"] = "态度为一般时"
}
local tagOverrides = {
["book_item"] = {
displayName = "所有[[书]]",
includeOriginalList = false
},
["category_egg"] = {
displayName = "所有蛋",
includeOriginalList = true
},
["forage_item_beach"] = {
displayName = "[[采集#沙滩|沙滩采集品]]",
includeOriginalList = true
},
["milk_item"] = {
displayName = "所有奶",
includeOriginalList = true
},
["category_cooking"] = {
displayName = "所有[[:分类:菜品|菜品]]",
includeOriginalList = false
},
["doll_item"] = {
displayName = "所有玩偶",
includeOriginalList = true
},
["alcohol_item"] = {
displayName = "所有酒",
includeOriginalList = true
},
["category_greens"] = {
displayName = "所有[[采集#可采集物品|采集品]]",
includeOriginalList = false
},
["category_fish"] = {
displayName = "所有[[鱼类一览|鱼]]",
includeOriginalList = false
},
["ancient_item"] = {
displayName = "所有[[古物]]",
includeOriginalList = false
}
}
local function cleanText(text)
if not text or type(text) ~= "string" then
return text
end
text = text:gsub("@", '<span class="player-name">玩家名</span>')
text = text:gsub("%$[hbslau]", "")
text = text:gsub("%$%d+", "")
text = text:gsub("##", "\n")
text = text:gsub("%s*%[%s*%d+%s*%]", '<span class="refuse-item">(拒绝并返还)</span>')
if not text:match("class=\"quotetable\"") then
text = text:gsub('“', '‘')
text = text:gsub('”', '’')
end
return text
end
local function processProbabilityText(text)
if not text or type(text) ~= "string" then
return text
end
local probability, text1, text2 = text:match("%$c%s+([%d%.]+)#(.-)#(.*)")
if probability and text1 and text2 then
text1 = cleanText(text1)
text2 = cleanText(text2)
local percent = math.floor(tonumber(probability) * 100)
local option1 = Helper.ExpandTemplate("模板:Squote", {text1 .. '<span class="trigger-chance">(' .. percent .. '% 的概率触发)</span>'})
local option2 = Helper.ExpandTemplate("模板:Squote", {text2 .. '<span class="trigger-chance">(' .. (100 - percent) .. '% 的概率触发)</span>'})
return option1 .. "\n" .. option2
end
return text
end
local function getItemDisplayName(itemId)
if itemId == "(O)126" or itemId == "126" then
return Helper.ExpandTemplate("模板:Name", {"Strange Doll (green)", class = "inline"})
elseif itemId == "(O)127" or itemId == "127" then
return Helper.ExpandTemplate("模板:Name", {"Strange Doll (yellow)", class = "inline"})
end
local englishName = ItemNames.getEnglishName(itemId)
if englishName and englishName ~= "" then
return Helper.ExpandTemplate("模板:Name", {englishName, class = "inline"})
end
return nil
end
local function getItemsByTag(tag)
local matchingItems = {}
local seenItems = {}
local seenNames = {}
for objId, tags in pairs(TagData) do
if type(tags) == "table" then
for _, contextTag in ipairs(tags) do
if contextTag == tag then
local fullItemId = objId:match("^%([A-Z]+%)") and objId or "(O)" .. objId
if not objId:match("^%([A-Z]+%)") and seenItems[fullItemId] then
break
end
local displayName = getItemDisplayName(fullItemId)
if displayName and not seenItems[fullItemId] then
local chineseName = ItemNames.getChineseName(fullItemId)
local isStrangeDoll = fullItemId == "(O)126" or fullItemId == "(O)127"
if isStrangeDoll or not seenNames[chineseName] then
table.insert(matchingItems, {id = fullItemId, display = displayName})
seenItems[fullItemId] = true
if chineseName then
seenNames[chineseName] = true
end
end
end
break
end
end
end
end
if #matchingItems > 0 then
table.sort(matchingItems, function(a, b)
local aNum = a.id:match("%(O%)(%d+)")
local bNum = b.id:match("%(O%)(%d+)")
if aNum and bNum then
return tonumber(aNum) < tonumber(bNum)
elseif aNum and not bNum then
return true
elseif not aNum and bNum then
return false
else
return a.id < b.id
end
end)
local displayNames = {}
for _, item in ipairs(matchingItems) do
table.insert(displayNames, item.display)
end
return table.concat(displayNames, "、")
end
return nil
end
-- =p.parseDialogue{args={"Abigail","AcceptGift_(O)SkillBook_4"}}
-- =p.parseDialogue{args={"Emily","AcceptGift_(O)60"}}
-- =p.parseDialogue{args={"Elliott","AcceptGift_(O)155"}}
-- =p.parseDialogue{args={"Haley","AcceptGift_(O)88"}}
function p.parseDialogue(frame)
local args = frame.args
local characterName = args[1]
local dialogueKey = args[2]
if not characterName then
return "错误:请提供角色名称"
end
local character = AcceptGiftData[characterName]
if not character then
return "错误:未找到角色 " .. characterName
end
if dialogueKey then
local dialogue = character[dialogueKey]
if not dialogue then
return "错误:未找到对话 " .. dialogueKey
end
if type(dialogue) == "string" then
if dialogue:match("%$c%s+") then
return processProbabilityText(dialogue)
else
return Helper.ExpandTemplate("模板:Squote", {cleanText(dialogue)})
end
end
return tostring(dialogue)
else
local result = {}
for key, text in pairs(character) do
if type(text) == "string" then
local processedText
if text:match("%$c%s+") then
processedText = processProbabilityText(text)
else
processedText = Helper.ExpandTemplate("模板:Squote", {cleanText(text)})
end
table.insert(result, string.format("%s\n%s", key, processedText))
end
end
return table.concat(result, "\n\n")
end
end
function p.parseDialogueTable(dialogueTable)
if type(dialogueTable) ~= "table" then
return nil
end
local result = {}
for characterName, dialogues in pairs(dialogueTable) do
result[characterName] = {}
if type(dialogues) == "table" then
for dialogueKey, dialogueText in pairs(dialogues) do
if type(dialogueText) == "string" then
local processedText = dialogueText
if processedText:match("%$c%s+") then
processedText = processProbabilityText(processedText)
else
processedText = Helper.ExpandTemplate("模板:Squote", {cleanText(processedText)})
end
result[characterName][dialogueKey] = processedText
else
result[characterName][dialogueKey] = dialogueText
end
end
else
result[characterName] = dialogues
end
end
return result
end
function p.getCharacterList(frame)
local result = {}
for characterName, _ in pairs(AcceptGiftData) do
table.insert(result, characterName)
end
return table.concat(result, "、")
end
-- =p.getGiftDialogues{args={"Haley"}}
-- =p.getGiftDialogues{args={"Elliott"}}
function p.getGiftDialogues(frame)
local npcName = frame.args[1] or frame:getParent().args[1]
if not npcName then
return "<!-- 请提供人物名称 -->"
end
local englishName = NPC.getEnglishName(npcName)
local npcDialogues = AcceptGiftData[englishName]
if not npcDialogues then
return "<!-- 未找到人物 -->"
end
if type(npcDialogues) ~= "table" then
return "<!-- 当前人物数据不是表格类型 -->"
end
local result = {}
local keys = {}
for k, v in pairs(npcDialogues) do
if type(k) == "number" and type(v) == "table" and v.key and v.value then
table.insert(keys, k)
end
end
if #keys == 0 then
return "<!-- 当前人物没有特殊对话 -->"
end
table.sort(keys)
for _, i in ipairs(keys) do
local dialogueEntry = npcDialogues[i]
local dialogueKey = dialogueEntry.key
local dialogueText = dialogueEntry.value
local processedText = dialogueText
if processedText:match("%$c%s+") then
processedText = processProbabilityText(processedText)
else
processedText = Helper.ExpandTemplate("模板:Squote", {cleanText(processedText)})
end
local itemName = "未知物品"
local itemId = dialogueKey:match("AcceptGift_(.+)")
if itemId then
local displayName = getItemDisplayName(itemId)
if displayName then
itemName = displayName
else
local attitude, tag = itemId:match("^([^_]+)_(.+)$")
if attitude and tag then
local override = tagOverrides[tag]
if override then
itemName = override.displayName
if attitude and attitudeMapping[attitude] then
itemName = itemName .. "(" .. attitudeMapping[attitude] .. ")"
end
if override.includeOriginalList then
local originalList = getItemsByTag(tag)
if originalList then
itemName = itemName .. '<br><span style="font-size: smaller;">' .. originalList .. '</span>'
end
end
else
local itemList = getItemsByTag(tag)
itemName = itemList or itemId
if attitude and attitudeMapping[attitude] then
itemName = itemName .. "(" .. attitudeMapping[attitude] .. ")"
end
end
else
itemName = itemId
end
end
else
itemName = dialogueKey
end
if englishName == "Leo" and dialogueKey == "AcceptGift_(O)StardropTea" then
local leoMainlandData = AcceptGiftData["LeoMainland"]
local leoMainlandDialogue = ""
if leoMainlandData then
for _, entry in pairs(leoMainlandData) do
if type(entry) == "table" and entry.key == "AcceptGift_(O)StardropTea" then
leoMainlandDialogue = entry.value
break
end
end
end
local leoGingerText = Helper.ExpandTemplate("模板:Squote", {cleanText(dialogueText) .. '<span class="trigger-chance">(位于姜岛时)</span>'})
local leoMainlandText = ""
if leoMainlandDialogue ~= "" then
leoMainlandText = Helper.ExpandTemplate("模板:Squote", {cleanText(leoMainlandDialogue) .. '<span class="trigger-chance">(位于鹈鹕镇时)</span>'})
end
if leoMainlandText ~= "" then
processedText = leoGingerText .. "\n" .. leoMainlandText
else
processedText = leoGingerText
end
end
table.insert(result, string.format("%s\n%s", itemName, processedText))
end
local output = {}
local pageName = NPC.getChineseName(englishName) or mw.title.getCurrentTitle().text
table.insert(output, "<h3>特殊</h3>")
table.insert(output, "向" .. pageName .. "赠送某些特别的礼物时,会触发特殊的对话。")
table.insert(output, "下列的对话从上往下判定,上方的对话优先级高于下方的对话。如果没有特殊对话,则会触发普通的对话。")
table.insert(output, table.concat(result, "\n\n"))
return table.concat(output, "\n\n")
end
local rudeCharacters = {
"Abigail", "Alex", "Clint", "George", "Haley", "Pam", "Sebastian", "Shane", "Wizard"
}
local function isRudeCharacter(characterName)
for _, name in ipairs(rudeCharacters) do
if name == characterName then
return true
end
end
return false
end
local function processSlashDialogue(text)
if not text or type(text) ~= "string" then
return text
end
if text:find("/") then
local parts = {}
for part in text:gmatch("[^/]+") do
table.insert(parts, part:match("^%s*(.-)%s*$"))
end
if #parts == 2 and parts[1] == parts[2] then
return parts[1]
else
if #parts == 2 then
local male = parts[1]
local female = parts[2]
local maleQuote = Helper.ExpandTemplate("模板:Squote", {male .. '<span class="trigger-chance">(男)</span>'})
local femaleQuote = Helper.ExpandTemplate("模板:Squote", {female .. '<span class="trigger-chance">(女)</span>'})
return maleQuote .. "\n" .. femaleQuote
else
return table.concat(parts, "/")
end
end
end
return text
end
-- 获取生日对话
-- =p.getBirthdayDialogues{args={"Alex"}}
-- =p.getBirthdayDialogues{args={"Emily"}}
function p.getBirthdayDialogues(frame)
local npcName = frame.args[1] or frame:getParent().args[1]
if not npcName then
return "<!-- 请提供人物名称 -->"
end
local englishName = NPC.getEnglishName(npcName)
local npcDialogues = AcceptBirthdayGiftData[englishName]
if not npcDialogues then
npcDialogues = {}
end
local isRude = isRudeCharacter(englishName)
local fallbackData = isRude and AcceptBirthdayGiftData["_FallbackDialogues_Rude"] or AcceptBirthdayGiftData["_FallbackDialogues_Polite"]
local preferenceMapping = {
["最爱"] = {"AcceptBirthdayGift_Loved", "AcceptBirthdayGift_Positive"},
["喜欢"] = {"AcceptBirthdayGift_Liked", "AcceptBirthdayGift_Positive"},
["一般"] = {"AcceptBirthdayGift_Neutral", "AcceptBirthdayGift_Positive"},
["不喜欢"] = {"AcceptBirthdayGift_Disliked", "AcceptBirthdayGift_Negative"},
["讨厌"] = {"AcceptBirthdayGift_Hated", "AcceptBirthdayGift_Negative"}
}
local result = {}
local processedGroups = {}
local groupOrder = {}
local preferenceOrder = {"最爱", "喜欢", "一般", "不喜欢", "讨厌"}
for _, preference in ipairs(preferenceOrder) do
local keys = preferenceMapping[preference]
local foundDialogues = {}
local usedKeys = {}
local searchOrder = {}
table.insert(searchOrder, {source = "npc", key = keys[1]})
table.insert(searchOrder, {source = "npc", key = keys[2]})
table.insert(searchOrder, {source = "fallback", key = keys[1]})
if keys[2] == "AcceptBirthdayGift_Positive" then
table.insert(searchOrder, {source = "fallback", key = "AcceptBirthdayGift_Positive_1"})
table.insert(searchOrder, {source = "fallback", key = "AcceptBirthdayGift_Positive_2"})
else
table.insert(searchOrder, {source = "fallback", key = keys[2]})
end
for _, searchItem in ipairs(searchOrder) do
local dialogue
if searchItem.source == "npc" then
dialogue = npcDialogues[searchItem.key]
else
dialogue = fallbackData[searchItem.key]
end
if dialogue then
table.insert(foundDialogues, dialogue)
table.insert(usedKeys, searchItem.key)
if searchItem.key == "AcceptBirthdayGift_Positive_1" and fallbackData["AcceptBirthdayGift_Positive_2"] then
table.insert(foundDialogues, fallbackData["AcceptBirthdayGift_Positive_2"])
table.insert(usedKeys, "AcceptBirthdayGift_Positive_2")
end
break
end
end
if #foundDialogues > 0 then
local groupKey = table.concat(usedKeys, "|")
if not processedGroups[groupKey] then
processedGroups[groupKey] = {}
table.insert(groupOrder, groupKey)
end
table.insert(processedGroups[groupKey], preference)
for i, dialogue in ipairs(foundDialogues) do
dialogue = processSlashDialogue(dialogue)
dialogue = cleanText(dialogue)
foundDialogues[i] = Helper.ExpandTemplate("模板:Squote", {dialogue})
end
end
end
for _, groupKey in ipairs(groupOrder) do
local preferences = processedGroups[groupKey]
local keys = {}
for key in groupKey:gmatch("[^|]+") do
table.insert(keys, key)
end
-- 获取对话内容
local dialogues = {}
for _, key in ipairs(keys) do
local dialogue
if npcDialogues[key] then
dialogue = npcDialogues[key]
else
dialogue = fallbackData[key]
end
if dialogue then
dialogue = processSlashDialogue(dialogue)
local processedDialogue = cleanText(dialogue)
if not processedDialogue:match("class=\"quotetable\"") then
processedDialogue = Helper.ExpandTemplate("模板:Squote", {processedDialogue})
end
table.insert(dialogues, processedDialogue)
end
end
if #dialogues > 0 then
local preferenceText
if #preferences == 1 then
preferenceText = preferences[1]
elseif #preferences == 2 then
preferenceText = preferences[1] .. "或" .. preferences[2]
else
local lastPref = table.remove(preferences)
preferenceText = table.concat(preferences, "、") .. "或" .. lastPref
end
local pageName = NPC.getChineseName(englishName) or mw.title.getCurrentTitle().text
table.insert(result, string.format("收到%s的礼物,%s会说:", preferenceText, pageName))
for _, dialogue in ipairs(dialogues) do
table.insert(result, dialogue)
end
end
end
if #result == 0 then
return "<!-- 该人物没有生日对话数据 -->"
end
return table.concat(result, "\n\n")
end
-- =p.getGiftTasteDialogue{args={"Robin", "love"}}
-- =p.getGiftTasteDialogue{args={"罗宾", "最爱"}}
function p.getGiftTasteDialogue(frame)
local npcName = frame.args[1] or frame:getParent().args[1]
local tasteType = frame.args[2] or frame:getParent().args[2]
if not npcName then
return "<!-- 请提供人物名称 -->"
end
if not tasteType then
return "<!-- 请提供礼物类型 -->"
end
local englishName = NPC.getEnglishName(npcName)
local normalizedType = string.lower(tasteType)
local typeMapping = {
["最爱"] = "love",
["喜欢"] = "like",
["一般"] = "neutral",
["不喜欢"] = "dislike",
["讨厌"] = "hate",
["love"] = "love",
["like"] = "like",
["neutral"] = "neutral",
["dislike"] = "dislike",
["hate"] = "hate"
}
local englishType = typeMapping[normalizedType]
if not englishType then
return "<!-- 无效的礼物类型:" .. tasteType .. " -->"
end
local npcData = GiftTastesData.npcs[englishName]
if not npcData then
return "<!-- 未找到人物:" .. englishName .. " -->"
end
local tasteData = npcData[englishType]
if not tasteData then
return "<!-- 未找到对应的礼物类型数据 -->"
end
local dialogue = tasteData.dialogue
if not dialogue or dialogue == "" then
return "<!-- 该人物没有对应类型的对话 -->"
end
local cleanedDialogue = cleanText(dialogue)
return Helper.ExpandTemplate("模板:Squote", {cleanedDialogue})
end
return p