欢迎大家来到沙石镇时光中文维基!本站编辑权限开放,欢迎加入中文维基 QQ 群「沙海时光」:372816689
目前正在进行全站数据更新,期间可能会存在显示异常的问题。

全站通知:

模块:Gift

来自沙石镇时光维基
跳到导航 跳到搜索

注意

目前该页面的代码逻辑与英维有一定差异,待更新。
由于该模块已被广泛使用,更新代码需要完全调试好确定无误再操作。

Functions

Giftable

If the first parameter is empty, it will use {{PAGENAME}}.

Source Result
{{#invoke:Gift|Giftable|驼牛奶}} 1
{{#invoke:Gift|Giftable|妮雅的香包}} (empty)
{{#invoke:Gift|Giftable|驼牛奶|yes|no}} yes
{{#invoke:Gift|Giftable|妮雅的香包|1|0}} 0

ItemRelationshipTableContent

Used in Template:Gifted_item.

Usually you only to use {{gifted item|驼牛奶}}

Source:

{|class="prettytable" style="text-align:center;"
|-
!style="width:18%;"|{{i|Gifting|Social gift|size=50px}}
![[Character]]s
|-
{{#invoke:Gift|ItemRelationshipTableContent|驼牛奶}}
|}

Result:

送礼 人物
喜欢.png 喜欢 (+5) 伯吉斯.png伯吉斯洛基.png洛基
喜欢.png 一般 (+3) 卡托莉.png卡托莉欧文.png欧文贾斯迪.png贾斯迪颜.png
喜欢.png 一般 (+2) 扎克.png扎克
喜欢.png 一般 (+1) 克丽丝蒂.png克丽丝蒂咕咕.png咕咕埃尔西.png埃尔西培波斯.png培波斯妮雅.png妮雅孩子.png孩子安迪.png安迪小叉.png小叉小黑.png小黑尼莫.png尼莫帕布洛.png帕布洛库珀.png库珀彭虎.png彭虎惟.png房时渺.png房时渺春.png朴丹苾.png朴丹苾杜蒂.png杜蒂格蕾丝.png格蕾丝梅丁.png梅丁欧内斯特.png欧内斯特沙沙.png沙沙洛根.png洛根海蒂.png海蒂狐獴.png狐獴玛奇朵.png玛奇朵玛蒂尔达.png玛蒂尔达玛贝尔.png玛贝尔班长.png班长瑞安.png瑞安简.png米安.png米安米格尔.png米格尔素馨.png素馨肥尾守宫.png肥尾守宫胡果.png胡果莫特爷爷.png莫特爷爷薇蒂.png薇蒂薇薇奶奶.png薇薇奶奶詹森.png詹森阔耳狐.png阔耳狐阿尔维奥.png阿尔维奥阿蜜拉.png阿蜜拉阿诺.png阿诺魔镜秀秀.png魔镜秀秀齐衡.png齐衡

How to update data

See Module:AssetItemPrototypeItem and Module:ItemId.


local Helper = require("Module:Helper")
local ItemHelper = require("Module:ItemHelper")
local ItemModule = require("Module:Item")
local ImageUnifier = require("Module:ImageUnifier")
local cache = require "mw.ext.LuaCache"
local NpcProtoData = require("Module:NpcProtoData")
local GiftData = Helper.LazyLoad("Module:AssetSendGiftDataGift")
local GiftItem = Helper.LazyLoad("Module:AssetGiftItemDataGiftItem")
local ItemId = Helper.LazyLoad("Module:ItemId")
local AssetNpcProtoDatas = Helper.LazyLoad("Module:AssetNpcProtoDatas")
local AssetItemChinese = Helper.LoadAsset("Module:AssetItemChinese")
local KEY_PREFIX = "Module:Gift"
local EXP_TIME = 172800

local favorLevels = {
    "Excellent",
    "Like",
    "Neutral",
    "Dislike",
    "Hate",
    "Refuse"
}

local qualityNames = {
    green = 1,
    blue = 2,
    purple = 3,
    outstanding = 1,
    perfect = 2,
    rare = 3
}

local specialGifts = {
    [ItemId["道歉小熊"]] = true,
    [ItemId["枯树枝"]] = true,
    [ItemId["同心结"]] = true,
    [ItemId["聚会邀请函"]] = true
}

local ChoiceType = {
    None = -1,
    Leave = 0,
    Talk = 1,
    Gift = 2,
    BranchMissionSubmit = 3,
    MainMissionSubmit = 4,
    Research = 5,
    PK = 6,
    Play = 7,
    Date = 8,
    CancelPlay = 9,
    CancelDate = 10,
    Interaction = 11,
    Photo = 12,
    BranchMissionReceive = 13,
    MainMissionReceive = 14,
    ResetProficiencyPoint = 15,
    AnimalCardFight = 16,
    OpenStore = 17,
    InquiryCooking = 18,
    Interactive = 19,
    EG_None = 256,
    EG_Chat = 257,
    EG_Stop = 258,
    EG_Parise = 259,
    EG_CasualTalk = 260,
    EG_AskWork = 261,
    EG_AskLike = 262,
    EG_Eat = 263,
    EG_HandInHand = 264,
    EG_Waist = 265,
    EG_Sleep = 266,
    EG_AskPast = 267,
    CustomStart = 1000,
    CustomType1 = 1000,
    CustomType2 = 1001,
    CustomType3 = 1002,
    CustomType4 = 1003,
    CustomEnd = 1004,
    CustomType5 = 1004,
    MagicMirror_Hire = 2000,
    MagicMirror_Chip = 2001,
    MagicMirror_Weather = 2002,
    MagicMirror_Cosmetic = 2003,
    RidableStay = 100000000,
    RidableHome = 100000001,
    RidableFollow = 100000002,
    RidableView = 100000003,
    RidableInteractive = 100000004,
    Pet_Recruit = 200000000,
    Pet_Default = 200000001,
    Pet_Dispatch = 200000002,
    Pet_Disport = 200000003,
    Pet_Follow = 200000004
}

-- APIs Part --

local p = {}

p.Giftable = function(frame)
    local hash = Helper.HashArgs(frame.args)
    local cacheKey = KEY_PREFIX .. "Giftable" .. hash

    if (cache.get(cacheKey)) then
        local result = cache.get(cacheKey)
        return result
    end

    local args = parseArgs(frame)
    local yes = frame.args[2]

    if yes == nil or yes == "" then
        yes = "1"
    end

    local no = frame.args[3]

    if no == nil or no == "" then
        no = ""
    end

    local result

    if GiftItem[args.itemId] == nil then
        result = no
    else
        result = yes
    end

    cache.set(cacheKey, result, EXP_TIME)
    return result
end

p.ItemRelationshipTableContent = function(frame)
    local cacheKey = KEY_PREFIX .. "ItemRelationshipTableContent" .. frame.args[1]

    if (cache.get(cacheKey)) then
        local result = cache.get(cacheKey)
        return result
    end

    local args = parseArgs(frame)

    if GiftItem[args.itemId] == nil then
        error(args.itemName .. ' ' .. args.itemId .. " is not giftable")
    end

    local results = getGiftRelationshipForEachNpc(args.itemId, args.quality)
    local result = formatItemRelationshipTable(results)
    cache.set(cacheKey, result, EXP_TIME)
    return result
end

p.CharacterGiftTableContent = function(frame)
    local npcName = frame.args.character

    if npcName == nil or npcName == "" then
        npcName = mw.getCurrentFrame():getParent():getTitle()
    end

    local rowTemplate = frame.args.row
    local npcId = p.getNpcId(npcName)

    local cacheKey = KEY_PREFIX .. "CharacterGiftTableContent" .. npcId
    local paramater = frame.args.row
    
    if paramater ~= nil and paramater ~= "" then
    	cacheKey = cacheKey .."|" .. paramater
    end
	local result = cache.get(cacheKey)
	function contains(str, substr)
	    local pos = string.find(str, substr)
	    if pos then
	        return true
	    else
	        return false
	    end
	end
    if (result) and contains(result, 'gift-list') then
        return result
    end

    local levelItems = {}

    for itemId, _ in pairs(GiftItem) do
        if ItemHelper.isImplemented(itemId) and not specialGifts[itemId] then
            local result = getGiftRelationship(npcId, itemId, ItemHelper.getBaseQuality(itemId))

            if result.special then
                if levelItems[result.level] == nil then
                    levelItems[result.level] = {}
                end

                local itemName = ItemHelper.getName(itemId)

                table.insert(levelItems[result.level], {
                    name = itemName,
                    value = result.value
                })
            end
        end
    end

    local rowArgs = {}

    for _, level in ipairs(favorLevels) do
        local items = levelItems[level] or {}

        table.sort(items, function(a, b)
            if a.value == b.value then
                return a.name < b.name
            else
                return a.value > b.value
            end
        end)

        local formatItems = Helper.Map(items, function(item)
            if item.value > 0 then
                return ItemHelper.addIconAndLink(item.name) .. " (+" .. item.value .. ")"
            else
                return ItemHelper.addIconAndLink(item.name) .. " (" .. item.value .. ")"
            end
        end)

        local itemsStr = table.concat(formatItems, "<br>")

		local levelStr = level
		
		if levelStr == "Excellent" then
		    levelStr = "非常喜欢"
		elseif levelStr == "Like" then
		    levelStr = "喜欢"
		elseif levelStr == "Neutral" then
		    levelStr = "一般"
		elseif levelStr == "Dislike" then
		    levelStr = "不喜欢"
		elseif levelStr == "Hate" then
		    levelStr = "讨厌"
		elseif levelStr == "Refuse" then
		    levelStr = "拒绝"
		end


		if levelStr ~= "一般" then
			table.insert(rowArgs, {
                level = levelStr,
                items = itemsStr
        })
		end
    
    end

    local rows = Helper.Map(rowArgs, function(args)
        return Helper.ExpandTemplate(rowTemplate, args)
    end)

    local result = table.concat(rows, "\n|-\n")
    cache.set(cacheKey, result, EXP_TIME)
    return result
end

p.AllGifts = function(frame)
    local cacheKey = KEY_PREFIX .. "AllGifts"

    if (cache.get(cacheKey)) then
        local result = cache.get(cacheKey)
        return result
    end

    local keys = {}
    local rows = {}

    for name, id in pairs(ItemId) do
        if GiftItem[id] ~= nil and ItemHelper.isImplemented(id) and name ~= "party invitation" then
            local quality = ItemHelper.getBaseQuality(id)
            local item = ItemHelper.addIconAndLink(name)
            local baseNeutralValue = tostring(getGiftFavor(id, quality, 0, "Neutral"))
            local results = getGiftRelationshipForEachNpc(id, quality)
            local notes = formatUniversal(results)
            local row = "|-\n|" .. item .. "||" .. baseNeutralValue .. "||" .. notes

            local key = ItemHelper.getSortKey(id)
            table.insert(keys, key)
            rows[key] = row
        end
    end

    table.sort(keys)
    local sortedRows = {}

    for i, key in ipairs(keys) do
        sortedRows[i] = rows[key]
    end

    local result = table.concat(sortedRows, "\n")
    cache.set(cacheKey, result, EXP_TIME)
    return result
end

p.characters_table = function()
    local ret = "<div class='table-responsive w-auto'>\n"
    ret = ret .. "<table class='table prettytable fandom-table sortable w-auto'>\n"
    ret = ret .. "<tr>" .. "<th class='align-middle text-center'>Name</th>"
              .. "<th class='align-middle text-center'>Birthday</th>"
              .. "<th class='align-middle text-center unsortable'>Gift Preferences</th>" .. "</tr>\n"

    for npcId, assetNpcProtoData in pairs(AssetNpcProtoDatas) do
        if (hasGiftInteractChoice(assetNpcProtoData.interactChoice)) then
            local row
            local npcName = getText(assetNpcProtoData.nameID)
            local cacheKey = KEY_PREFIX .. "characters_table" .. npcId

            if (cache.get(cacheKey)) then
                row = cache.get(cacheKey)
            end

            if (row) then
            else
                row = ""

                local season = NpcProtoData.season({
                    args = {
                        [1] = npcName
                    }
                })

                local birthday = assetNpcProtoData.birthday
                local splitBirthday = {}

                -- Split the string by the '.' delimiter and add the parts to a table
                for part in string.gmatch(birthday, "([^%.]+)") do
                    table.insert(splitBirthday, part)
                end

                -- If the second part has only one character, add a leading zero
                if #splitBirthday == 2 and #splitBirthday[2] == 1 then
                    splitBirthday[2] = "0" .. splitBirthday[2]
                end

                -- Join the parts back together with a '.' separator
                birthday = table.concat(splitBirthday, ".")

                local levelItems = {}

                for itemId, _ in pairs(GiftItem) do
                    if ItemHelper.isImplemented(itemId) and not specialGifts[itemId] then
                        local result = getGiftRelationship(npcId, itemId, ItemHelper.getBaseQuality(itemId))

                        if (result) then
                            if result.special then
                                if levelItems[result.level] == nil then
                                    levelItems[result.level] = {}
                                end

                                local itemName = ItemHelper.getName(itemId)

                                table.insert(levelItems[result.level], {
                                    name = itemName,
                                    value = result.value
                                })
                            end
                        end
                    end
                end

                local levelItemsCount = 0

                for k, v in pairs(levelItems) do
                    levelItemsCount = levelItemsCount + 1
                end

                if (levelItems and levelItemsCount >= 1) then
                    row = row .. "<tr>\n"

                    row = row .. "<th id='" .. npcName .. "' class='text-center'><div>" .. ImageUnifier.GetImagesMain({
                        npcName
                    }, {
                        link = npcName
                    }, "large", false) .. "</div><div>[[" .. npcName
                              .. "]]</div></th><td class='text-center' data-sort-value='" .. birthday
                              .. "'><div class='m-1'>" .. ImageUnifier.GetImagesMain({
                        "Season " .. season
                    }, {
                        link = "Calendar#" .. season
                    }, "medium", false) 
                    .. "</div><div class='m-1'>" .. birthday .. "</div>"
                              .. "</td><td class='align-middle text-center'>"

                    local rowArgs = {}

                    for _, level in ipairs(favorLevels) do
                        local items = levelItems[level] or {}

                        -- hide Neutrals, and empty Refuse
                        if (level == "Refuse" and #items <= 0) then
                            items = nil
                        elseif (level == "Neutral") then
                            items = nil
                        else
                        end

                        if (items) then
                            table.sort(items, function(a, b)
                                if a.value == b.value then
                                    return a.name < b.name
                                else
                                    return a.value > b.value
                                end
                            end)

                            local formatItems = Helper.Map(items, function(item)
                                if item.value > 0 then
                                    return ItemHelper.addIconAndLink(item.name) .. " (+" .. item.value .. ")"
                                else
                                    return ItemHelper.addIconAndLink(item.name) .. " (" .. item.value .. ")"
                                end
                            end)

                            local itemsStr = table.concat(formatItems, "<br>")

                            if level == "Excellent" then
                                table.insert(rowArgs, {
                                    level = "Love",
                                    items = itemsStr
                                })
                            else
                                table.insert(rowArgs, {
                                    level = level,
                                    items = itemsStr
                                })
                            end
                        else
                        end
                    end

                    for i, rowArg in pairs(rowArgs) do
                        local level = rowArg.level
                        local items = rowArg.items
                        local levelIcon

                        if (level == "Love") then
                            levelIcon = "非常喜欢"
                        elseif (level == "Like") then
                            levelIcon = "喜欢"
                        elseif (level == "Neutral") then
                            levelIcon = "喜欢"
                        elseif (level == "Dislike") then
                            levelIcon = "不喜欢"
                        elseif (level == "Hate") then
                            levelIcon = "讨厌"
                        elseif (level == "Refuse") then
                            levelIcon = "不喜欢"
                        end

                        if (i == 1) then
                        else
                            row = row .. "<hr class='m-1' style='border:0px solid; border-top:1px solid #f1cf6280;'>\n"
                        end

                        row = row .. "<div class='row'><div class='col-1 fw-bold m-1'><div>\n"
                                  .. ImageUnifier.GetImagesMain({
                                levelIcon
                            }, {
                                link = ""
                            }, "small", false) .. "</div><div>" .. level
                                  .. "</div></div><div class='col text-start m-1' style='-moz-column-count:2;-webkit-column-count:2;'>\n"
                        row = row .. items .. "\n"
                        row = row .. "</div></div>\n"
                    end

                    row = row .. "</td>\n"
                    row = row .. "</tr>\n"
                    cache.set(cacheKey, row, EXP_TIME)
                else
                end
            end

            ret = ret .. row .. "\n"
        end
    end

    ret = ret .. "</table>\n"
    ret = ret .. "</div>\n"
    return ret
end

-- Formatting Part --
function parseArgs(frame)
    local args = {}

    if frame.args[1] and frame.args[1] ~= "" then
        args.itemName = frame.args[1]
    else
        args.itemName = frame:getParent():getTitle()
    end

    args.itemId = ItemHelper.getId(args.itemName)
    if args.itemId == nil then
        error("Cannot find item " .. args.itemName)
    end

    local hasArg = {}
    for key, value in pairs(frame.args) do
        if key ~= 1 then
            hasArg[value:lower()] = true
        end
    end

    for name, value in pairs(qualityNames) do
        if hasArg[name] then
            args.quality = value
        end
    end

    return args
end

function formatItemRelationshipTable(results)
    local levelOrder = {
        Excellent = 1,
        Like = 2,
        Neutral = 3,
        Dislike = 4,
        Hate = 5,
        Refuse = 6
    }

    local rows = {}
    local rps = {}
    for npcName, result in pairs(results) do
        local key
        if result.level == "Refuse" then
            key = levelOrder.Refuse * 1000
        else
            key = levelOrder[result.level] * 1000 - result.value
        end
        if rows[key] == nil then
            rows[key] = {}
            rps[key] = result
        end
        table.insert(rows[key], npcName)
    end

    local rowKeys = {}
    for key, _ in pairs(rows) do
        table.insert(rowKeys, key)
    end
    table.sort(rowKeys)

    local rowTexts = {}
    for _, key in ipairs(rowKeys) do
        local value = rps[key].value
        local level = rps[key].level
        if level == "Excellent" then
            level = "Love"
        end

        local icons = {
            Love = "非常喜欢",
            Like = "喜欢",
            Neutral = "喜欢",
            Dislike = "不喜欢",
            Hate = "讨厌",
            Refuse = "不喜欢"
        }
        local pre = {
            Love = "非常喜欢",
            Like = "喜欢",
            Neutral = "一般",
            Dislike = "不喜欢",
            Hate = "讨厌",
            Refuse = "拒绝"
        }
        local icon = ImageUnifier.GetImagesMain({
            icons[level]
        }, {
            link = "gifting"
        }, "24px")
        local col1 = "|" .. icon .. " '''" .. pre[level]
        if level ~= "Refuse" then
            if value > 0 then
                col1 = col1 .. " (+" .. value .. ")'''"
            else
                col1 = col1 .. " (" .. value .. ")'''"
            end
        end

        local npcs = {}
        local npcNames = rows[key]
        table.sort(npcNames)
        for _, npcName in ipairs(npcNames) do
            local icon = ImageUnifier.GetImagesMain({
                npcName
            }, {
                link = npcName
            }, "text")
            local npc = icon .. "[[" .. npcName .. "]]"
            if level == "Refuse" and results[npcName].value ~= 0 then
                npc = npc .. " (" .. results[npcName].value .. ")"
            end
            table.insert(npcs, npc)
        end
        local col2 = "|style=\"text-align:left\"|" .. table.concat(npcs, " • ")

        table.insert(rowTexts, col1 .. "\n" .. col2)
    end

    return table.concat(rowTexts, "\n|-\n")
end

function formatUniversal(results)
    local levelCount = {}
    local total = 0
    for _, result in pairs(results) do
        if levelCount[result.level] == nil then
            levelCount[result.level] = 0
        end
        levelCount[result.level] = levelCount[result.level] + 1
        total = total + 1
    end

    local universalLevel = nil
    for level, count in pairs(levelCount) do
        if total - count <= 3 then
            universalLevel = level
            break
        end
    end

    if universalLevel == nil then
        return ""
    end

    local exceptNpcs = {}
    for npcName, result in pairs(results) do
        if result.level ~= universalLevel then
            table.insert(exceptNpcs, npcName)
        end
    end
    table.sort(exceptNpcs)

    if universalLevel == "Excellent" then
        universalLevel = "Love"
    end
    local ret = "Universal " .. universalLevel:lower()
    if #exceptNpcs > 0 then
        ret = ret .. " except [[" .. table.concat(exceptNpcs, "]], [[") .. "]]"
    end
    return ret
end

-- Main Part --

function getGiftRelationshipForEachNpc(itemId, quality)
    local hash = Helper.HashArgs(itemId, quality)
    local cacheKey = KEY_PREFIX .. "getGiftRelationshipForEachNpc" .. hash

    if (cache.get(cacheKey)) then
        local result = cache.get(cacheKey)
        return result
    end

    local ret = {}

    for npcId, npc in pairs(AssetNpcProtoDatas) do
        if (hasGiftInteractChoice(npc.interactChoice)) then
            local npcName = getText(npc.nameID)
            local giftRelationship = getGiftRelationship(npcId, itemId, quality)

            if (npcName and giftRelationship) then
                ret[npcName] = giftRelationship
            else
            end
        end
    end

    cache.set(cacheKey, ret, EXP_TIME)
    return ret
end

function getGiftRelationship(npcId, itemId, quality)
    local hash = Helper.HashArgs(npcId, itemId, quality)
    local cacheKey = KEY_PREFIX .. "getGiftRelationship" .. hash

    if (cache.get(cacheKey)) then
        local result = cache.get(cacheKey)
        return result
    end

    local giftData = GiftData[npcId]
    local gain = getGiftGainInfo(npcId, giftData, itemId)

    if (gain) then
        local value = getGiftFavor(itemId, quality, gain.value, gain.level)
        local isSpecial = (gain.value ~= 0 or gain.level ~= "Neutral")

        local result = {
            value = value,
            level = gain.level,
            special = isSpecial
        }

        cache.set(cacheKey, result, EXP_TIME)
        return result
    else
    end
end

-- Helper Part --

function getGiftGainInfo(npcId, giftData, itemId)
    local giftItem = GiftItem[itemId]
    local levels = {
        "Excellent",
        "Like",
        "Dislike",
        "Hate",
        "Refuse"
    }

    for _, level in ipairs(levels) do
        if giftData and anyTagId(giftData["TagId" .. level], giftItem.tagA) then
            return {
                value = getGiftGainValue(giftData["FavorValues_" .. level], giftItem),
                level = level
            }
        end
    end

    if (giftData) then
        return {
            value = getGiftGainValue(giftData.FavorValues_Neutral, giftItem),
            level = "Neutral"
        }
    else
    end
end

function anyTagId(list1, list2)
    if (list1) then
        for _, x in ipairs(list1) do
            if (list2) then
                for _, y in ipairs(list2) do
                    if x == y then
                        return true
                    end
                end
            end
        end
    end

    return false
end

function getGiftGainValue(giftFavorValue, giftItemData)
    if (giftFavorValue and giftFavorValue.SpecialValues) then
        for _, special in ipairs(giftFavorValue.SpecialValues) do
            if (giftItemData and giftItemData.tagB) then
                for _, tag in ipairs(giftItemData.tagB) do
                    if tag == special.InventoryTagID then
                        return special.GainValue
                    end
                end
            end
        end
    end

    return giftFavorValue.DefaultGainValue
end

function getGiftFavor(itemId, gradeType, originalFavor, resultType)
    local hash = Helper.HashArgs(itemId, gradeType, originalFavor, resultType)
    local cacheKey = KEY_PREFIX .. "getGiftFavor" .. hash

    if (cache.get(cacheKey)) then
        local result = cache.get(cacheKey)
        return result
    end

    if (resultType) then
        local result

        if resultType == "Hate" then
            result = -5 + originalFavor
        end

        if (result) then
        else
            if resultType == "Refuse" then
                result = originalFavor
            end

            if (result) then
            else
                local low = {
                    Dislike = -3,
                    Neutral = 1,
                    Like = 5,
                    Excellent = 10
                }

                local high = {
                    Dislike = -1,
                    Neutral = 5,
                    Like = 10,
                    Excellent = 20
                }

                local ret = low[resultType] + (high[resultType] - low[resultType]) * getRegularFavor(itemId, gradeType)
                                + originalFavor
                -- round to even
                local floor = math.floor(ret)

                if ret - floor == 0.5 then
                    if floor % 2 == 1 then
                        result = floor + 1
                    else
                        result = floor
                    end
                end

                if (result) then
                else
                    result = math.floor(ret + 0.5)
                end
            end
        end

        cache.set(cacheKey, result, EXP_TIME)
        return result
    end
end

function getRegularFavor(itemId, gradeType)
    local hash = Helper.HashArgs(itemId, gradeType)
    local cacheKey = KEY_PREFIX .. "getRegularFavor" .. hash

    if (cache.get(cacheKey)) then
        local result = cache.get(cacheKey)
        return result
    end

    local sellPrice = ItemModule.getSellPrice(itemId, gradeType, true)

    if (sellPrice) then
        local x = sellPrice ^ 1.1
        local result = x / (x + 50)
        cache.set(cacheKey, result, EXP_TIME)
        return result
    end
end

function getText(id)
    if (AssetItemChinese[id]) then
        return AssetItemChinese[id]
    end
end

function hasGiftInteractChoice(interactChoice)
    for k, v in pairs(interactChoice) do
        if (v == 2 or ChoiceType[v] == 2) then
            return true
        end
    end
end

p.getNpcId = function(name)
    for npcId, npc in pairs(AssetNpcProtoDatas) do
        if (getText(npc.nameID) and name and getText(npc.nameID):lower() == name:lower()) then
            return npcId
        else
        end
    end
end

--

p.debug = function()
    Helper.ExpandTemplate = Helper.ExpandTemplateDebug

    local args = {
        row = "CharacterGiftTable/row",
        character = "Logan"
    }

    local frame = {
        args = args
    }

    -- for a,b in pairs(AssetNpcProtoDatas)do
    -- local cacheKey = "Module:Gift" .. "characters_table" .. a
    -- cache.delete(cacheKey)
    -- end

    local result = p.characters_table(frame)
    mw.log(result)
end

return p