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

全站通知:

模块:Store

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

Parameters

All functions in this module accept one optional parameter, the item name.

If no parameter is provided, PAGENAME will be used as item name.

Functions

ItemBuybackLocations

Which stores buy this item.

Source Result
{{#invoke:Store|ItemBuybackLocations|料理大师}} 十字口建筑商店
商会商店
梯坎百货
神秘商人
美味特饮商店
蓝月亮餐馆
迷你园艺店
镇政商店
{{#invoke:Store|ItemBuybackLocations|残破的剑}}

ItemFromStores

Which stores sell this item.

Source Result
{{#invoke:Store|ItemFromStores|麦草}} 农场杂货铺
协会售水处
协会温室
{{#invoke:Store|ItemFromStores|料理大师}} 金鹅币中心

ItemObtainingStoresTable

Generate the Purchasing table in Obtaining section.

See Template:ItemObtainingStores/table

ItemPurchasePrice

buy (PURCHASE PRICE) in item infobox.

Source Result
{{#invoke:Store|ItemPurchasePrice|稳健探险家背心}} 金币.png1,302
{{#invoke:Store|ItemPurchasePrice|咖啡茶树种子}} 金鹅币.png5
{{#invoke:Store|ItemPurchasePrice|妮雅的香包}} (empty)

How to update data

See Module:AssetItemPrototypeItem and Module:ItemId.


local Helper = require("Module:Helper")
local ImageUnifier = require("Module:ImageUnifier")
local ItemHelper = require("Module:ItemHelper")
local cache = require "mw.ext.LuaCache"
local ItemPrototype = Helper.LazyLoad("Module:AssetItemPrototypeItem")
local GroupProduct = Helper.LazyLoad("Module:AssetGroupProductBaseDataGroupGoods")
local SellProduct = Helper.LazyLoad("Module:AssetSellProductBaseDataGoods")
local StoreBaseData = Helper.LazyLoad("Module:AssetStoreBaseDataShop")
local Text = Helper.LoadAsset("Module:AssetItemChinese")
local StoreGoods = Helper.LazyLoad("Module:StoreGoods")
local ItemId = Helper.LazyLoad("Module:ItemId")
local p = {}
local KEY_PREFIX = "Module:Store"
local EXP_TIME = 172800

function getText(id)
    return Text[id]
end

local function identifyStore(nameOrId)
    -- There are many Vending Machine stores, so we need to be able to use 
    -- either an ID or a name as our parameter.
    for storeId, store in pairs(StoreBaseData) do
        local storeName = getText(store.shopName)

        if tostring(storeId) == tostring(nameOrId) or storeName == nameOrId then
            return storeId, storeName
        end
    end
    
    return nil, nil
end

-- APIs --
p.ItemBuybackLocations = function(frame)
    local itemName = frame.args[1]
    local cacheKey = KEY_PREFIX .. "ItemBuybackLocations" .. itemName

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

    local itemId = getItemId(itemName)

    if itemId == nil then
        error("Bad item name: " .. itemName)
    end

    local stores = p.getItemBuybackStores(itemId)

    if stores == nil then
        return ""
    elseif #stores == 0 then
        return frame.args[2] or ""
    end

    local result = "[[" .. table.concat(stores, "]]<br>[[") .. "]]"
    cache.set(cacheKey, result, EXP_TIME)
    return result
end

p.BuybackTableContent = function(frame)
    local storeName = frame.args[1]
    local cacheKey = KEY_PREFIX .. "BuybackTableContent" .. storeName
    cache.delete(cacheKey)

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

    local store = nil

    for _, s in pairs(StoreBaseData) do
        if getText(s.shopName):lower() == storeName:lower() then
            store = s
            break
        end
    end

    if store == nil then
        error("Bad store name: " .. storeName)
    end

    local itemNames = getStoreBuybackItems(store)
    local rows = {}

    for i, itemName in ipairs(itemNames) do
        local item = ItemPrototype[ItemId[itemName:lower()]]
        local iconFile, _ = itemName:gsub(":", "-")

        if item and item.maleIconPath == "Item_InstructionBook" then
            iconFile = "Item_InstructionBook"
        end

        local link = itemName

        if not ItemHelper.isImplemented(itemName) then
            link = ""
            iconFile = "DungeonItem_QuestionMark.png"
        end

        if (string.find(string.lower(itemName), "piece") and itemName:match("^(.*)%d$")) then
            link = ""
        end

        local icon = ImageUnifier.GetImagesMain({
            iconFile
        }, {
            caption = itemName,
            link = link
        }, "text", true)

        if link and link ~= "" then
            rows[i] = icon .. "[[" .. itemName .. "]]"
        else
            rows[i] = icon .. itemName
        end
    end

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

p.getItemFromStores = function(itemId)
    local stores = {}

    for storeId, goods in pairs(StoreGoods) do
        for _, good in ipairs(goods) do
            if good.itemId == itemId then
                local shopName = getText(StoreBaseData[storeId].shopName)
                local added = false

                for storeIndex, store in pairs(stores) do
                    if (shopName:lower() == store:lower()) then
                        added = true
                    else
                    end
                end

                if (added) then
                else
                    table.insert(stores, shopName)
                    break
                end
            end
        end
    end

    return stores
end

p.getItemConditions = function(itemId)
    local conditions = {}
    for storeId, goods in pairs(StoreGoods) do
        for _, good in ipairs(goods) do
            if good.itemId == itemId then
                if good.condition ~= nil then
                    return formatCondition(good.condition)
                end
            end
        end
    end
    return stores
end

p.ItemFromStores = function(frame)
    local itemName = frame.args[1]
    local itemId = getItemId(itemName)
    local stores = p.getItemFromStores(itemId)
    if #stores == 0 then
        error("Item cannot be purchased: " .. itemName)
    end
    table.sort(stores)
    return "[[" .. table.concat(stores, "]]<br>[[") .. "]]"
end

function ItemObtainingStoresTable_nocache(frame)
	local itemName = frame.args[1]
    local goods = findGoods(itemName, false)

    local hasCondition = nil

    if (goods) then
        for _, good in ipairs(goods) do
            if good.condition ~= nil then
                hasCondition = "1"
            end
        end
    end

    local header = expandTemplate("ItemObtainingStores/header", {
        condition = hasCondition
    })

    local rows = {}
	local count = 1
    if (goods) then
        for _, good in ipairs(goods) do
        	count = count + 1
            local args = {}
            args.store = good.storeName
            args.amount = good.amount
            args.price = good.price

            if (good.currency) then
                args.currency = good.currency:lower()
            else
            end

            args.rate = good.priceRate or ""

            if hasCondition then
                args.condition = formatCondition(good.condition)
            end

            local row = expandTemplate("ItemObtainingStores/row", args)
            if (args.store ~= nil) then -- 报错
            	rows[args.store] = row
            else
            	rows[count] = row
            end
        end
    end

    local concatedRows = ""

    for storeName, row in pairs(rows) do
        local _, matchStart, matchEnd = string.find(concatedRows, storeName)

        if matchStart then
        else
            concatedRows = concatedRows .. "\n" .. row
        end
    end

    return mw.getCurrentFrame():preprocess(header .. "\n" .. concatedRows .. "\n|}")
end

p.ItemObtainingStoresTable = Helper.Cached(
    ItemObtainingStoresTable_nocache,
    'Store|ItemObtainingStoresTable',
    function (frame) return frame.args[1] end,
    1
)
-- 英维为了修改某个 bug 改成了 KEY_PREFIX .. '|ItemObtainingStoresTable'

p.StockTable = function(frame)
    local storeId, storeName = identifyStore(frame.args[1])
    local storeName2 = frame.args[2]
    local goods = StoreGoods[storeId]
    local hasCondition = false
    for _, good in ipairs(goods) do
        if good.condition ~= nil then
            hasCondition = "1"
        end
    end
    local header = expandTemplate("StoreStock/header", {
        [1] = storeName,
        [2] = storeName2,
        condition = hasCondition
    })
    local rows = {}
    for _, good in ipairs(goods) do
        local args = {}
        args.item = ItemHelper.getName2(good.itemId)
        args.amount = good.amount
        args.restock = good.restock
        args.price = good.price
		if good.itemId > 80000000 then
            args.book = args.item
        end
        if (good.currency) then
            args.currency = good.currency:lower()
        else
        end

        args.rate = good.priceRate or ""
        if hasCondition then
            args.condition = formatCondition(good.condition, true)
            args.condition = args.condition:gsub("Start ", "触发")
            args.condition = args.condition:gsub("End ", "完成")
        end
        local row = expandTemplate("StoreStock/row", args)
        table.insert(rows, row)
    end
    return header .. "\n" .. table.concat(rows, "\n") .. "\n|}"
end

function getItemPurchasePrice_nocache(itemId)
    local goods = findGoodsById(itemId)

    if goods == nil then
        return nil
    end

    local low = nil
    local high = nil
    local currency = nil
    for _, good in ipairs(goods) do
        if good.currency == "Gols" then
            currency = "Gols"
            if low == nil or good.unitPrice < low then
                low = good.unitPrice
            end
            if high == nil or good.unitPrice > high then
                high = good.unitPrice
            end
        end
    end
    if currency == nil then
        low = goods[1].price
        high = goods[1].price
        currency = goods[1].currency
    end

    local currencyStr = " " .. expandTemplate("B", {
        currency
    })
    local lang = mw.getContentLanguage()
    if low == high then
        return currencyStr .. lang:formatNum(low)
    else
        return currencyStr .. lang:formatNum(low) .. "~" .. lang:formatNum(high)
    end
end

p.getItemPurchasePrice = getItemPurchasePrice_nocache
-- 需要绕过缓存
-- Helper.Cached(
--     getItemPurchasePrice_nocache,
--     "Store|getItemPurchasePrice",
--     nil,
--     2
-- )

p.ItemPurchasePrice = function(frame)
    local itemName = frame.args[1]
    local default = frame.args[2]

    local cacheKey = KEY_PREFIX .. "ItemPurchasePrice" .. itemName
    cache.delete(cacheKey)

    local itemId = getItemId(itemName)
    local result = p.getItemPurchasePrice(itemId) or default
    return result
end

-- Deprecated, for compatibility
p.ItemPurchaseCurrency = function(frame)
    local itemName = frame.args[1]
    local goods = findGoods(itemName)
    if goods == nil or goods[1].currency == "Gols" then
        return ""
    else
        return goods[1].currency
    end
end

p.getItemSellPrice = function(itemId, default)
    local cacheKey = KEY_PREFIX .. "getItemSellPrice" .. itemId
	cache.delete(cacheKey)
	-- 修改了货币和金额的排序,需要更新缓存
    if (cache.get(cacheKey)) then
        local result = cache.get(cacheKey)
        return result
    end

    local price = p.calcSellPrice(itemId)

    if price == nil then
        return default or ""
    end

    local result = expandTemplate("B", {
        "Gols"
    }) .. mw.getContentLanguage():formatNum(price)
    cache.set(cacheKey, result, EXP_TIME)
    return result
end

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

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

    local itemId = getItemId(itemName)
    local result = p.getItemSellPrice(itemId, frame.args[2])
    cache.set(cacheKey, result, EXP_TIME)
    return result
end

-- Main --

function p.getItemBuybackStores(itemId)
    local item = ItemPrototype[itemId]
    if item.cantSold ~= 0 then
        return nil
    end
    local hasTag = {}
    for _, tag in ipairs(item.itemTag) do
        hasTag[tag] = true
    end
    local storeNames = {}
    for _, store in pairs(StoreBaseData) do
    	if store.recycle then
        	for _, idValue in ipairs(store.recycle) do
            	if hasTag[idValue.id] then
            		local name = getText(store.shopName)
            		if name ~= "自动贩卖机" then  -- FIXME
                	    table.insert(storeNames, getText(store.shopName))
                	end
	                break
    	        end
        	end
        end
    end
    table.sort(storeNames)
    return storeNames
end

function getStoreBuybackItems(store)
    local acceptTag = {}
    for _, idValue in ipairs(store.recycle) do
        acceptTag[idValue.id] = true
    end

    local itemNames = {}
    for name, itemId in pairs(ItemId) do
        local item = ItemPrototype[itemId]
        if item.cantSold == 0 then
            for _, tag in ipairs(item.itemTag) do
                if acceptTag[tag] then
                    table.insert(itemNames, name)
                end
            end
        end
    end
    table.sort(itemNames)
    return Helper.Map(itemNames, ItemHelper.restoreCase)
end

function p.calcSellPrice(itemId)
    local item = ItemPrototype[itemId]
    if item.cantSold == 1 then
        return nil
    end

    local baseQuality = nil
    for quality = 1, 4 do
        if item.gradeWeight[quality] > 0 then
            baseQuality = quality
            break
        end
    end
    local qualityFactors = {
        1,
        1,
        1.25,
        1.6
    }

    local price = item.sellPrice.id0 / item.sellPrice.id1 * qualityFactors[baseQuality]
    if item.sellPrice.id1 == 1 then
        price = math.floor(price)
    end
    return price
end

-- Helpers --

function getItemId(itemName)
    local name = itemName

    if name == nil then
        name = mw.getCurrentFrame():getParent():getTitle()
    end

    name, _ = name:gsub("&#(%d+);", function(n)
        return string.char(n)
    end)

    local id = ItemId[name:lower()]

    if (id == nil and name == "Spicy Bean Paste (ingredient)") then
        id = 15000170;
    end

    if id == nil then
    	-- 19110005 = GlassId.Workaround for non-datamined items.
    	-- This defaults to "Cannot be purchased"
        -- error("Cannot find item: " .. itemName)
        id = 19110005;
    end

    return id
end

function expandTemplate(title, args)
    return mw.getCurrentFrame():expandTemplate{
        title = title,
        args = args
    }
end

function findGoodsById(itemId, assertPurchasable)
    local keys = {}
    local goods = {}
	local ret = {}
	local count = 1
    for storeId, storeGoods in pairs(StoreGoods) do
        for i, good in ipairs(storeGoods) do
            if good.itemId == itemId then
                local storeName = getText(StoreBaseData[storeId].shopName)
                ret[count] = {}
		        ret[count].storeName = storeName
                local key = storeName .. " " .. string.format("%04d", i)
                table.insert(keys, key)
                goods[key] = good
                ret[count].amount = goods[key].amount
		    	ret[count].currency = goods[key].currency
		    	ret[count].itemId = goods[key].itemId
		    	ret[count].price = goods[key].price
		    	ret[count].priceRate = goods[key].priceRate
		    	ret[count].restock = goods[key].restock
		    	ret[count].unitPrice = goods[key].unitPrice
		    	count = count + 1
            end
        end
    end

    if #keys == 0 then
        if assertPurchasable then
            error("Item cannot be purchased: " .. ItemHelper.getName(itemId))
        else
            return nil
        end
    end

    table.sort(keys)
    return ret
end

function findGoods(itemName, assertPurchasable)
    local itemId = getItemId(itemName)
    return findGoodsById(itemId, assertPurchasable)
end

function formatCondition(condition, short)
    if condition == nil then
        return "无"
    end
    if type(condition) == "string" then
        return condition
    end
    local mission = expandTemplate("m", {
        condition[2]
    })
    if short and condition[1]:sub(1, 9) == "Complete " then
        return mission
    end
    if short and condition[1]:sub(1, 12) == "Next day of " then
        return mission
    end
    local ret, _ = condition[1]:gsub("MISSION", mission)
    return ret
end

function getText(id)
    return Text[id]
end

--

p.debug = function()
    local args = {
        --"Rope Knot Toy",
        "大花犀牛角盆栽"
    }

    local frame = { args = args }

    expandTemplate = function(title, args)
        ret = "{{" .. title
        for k, v in pairs(args) do
            ret = ret .. "|" .. k .. "=" .. v
        end
        return ret .. "}}"
    end

    local r = p.ItemPurchasePrice(frame)
    mw.logObject(r)
end

p.debug_new = function()
    local args = {
        --"Rope Knot Toy",
        "大花犀牛角盆栽"
    }

    local frame = { args = args }

    expandTemplate = function(title, args)
        ret = "{{" .. title
        for k, v in pairs(args) do
            ret = ret .. "|" .. k .. "=" .. v
        end
        return ret .. "}}"
    end

    local r = p.ItemPurchasePrice(frame)
    mw.logObject(r)
end

function p.makeStoreDataForCooking()
	local iteminfo = {}
	local itemProto = mw.loadData("Module:AssetItemPrototypeItem")
	for _, itemObj in ipairs(mw.loadData("Module:Cooking/data")) do
		local itemId = itemObj.id
		local item = {
			id = itemId,
			buy_price = itemProto[itemId].buyPrice or false,
			buy_stores = p.getItemFromStores(itemId) or false,
			sell_price = p.calcSellPrice(itemId) or false,
			sell_stores = p.getItemBuybackStores(itemId) or false,
			condition = p.getItemConditions(itemId) or false,
		}
		for k, v in pairs(itemObj) do
			item[k] = v
		end
		mw.log("\t" .. Helper.dumpPretty(item, 1) .. ",")
		-- iteminfo[name] = item
	end
	return itemInfo
end

return p