维护提醒

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