Stardew
全站通知:

模块:FishPond

来自星露谷物语
跳到导航 跳到搜索

此模块的文档可以在模块:FishPond/doc创建

-- 宗旨:能用就行


local Helper = require("Module:Helper")
local ID = require("Module:ID")
local Object = require("Module:Object")
local Name = require("Module:Name")
local English = require("Module:English")
local FishPondData = Helper.LazyLoad('Module:FishPond/Data')
local p = {}

function tablesEqual(t1, t2)
    if t1 == t2 then
        return true
    end
    if type(t1) ~= "table" or type(t2) ~= "table" then
        return false
    end
    for key, value in pairs(t1) do
    	if not tableContains(t2, value) then return false end
    end

    for key, value in pairs(t2) do
        if not tableContains(t1, value) then return false end
    end
    return true
end

function tablesEqual2(t1, t2)
    if t1 == t2 then
        return true
    end
    if type(t1) ~= "table" or type(t2) ~= "table" then
        return false
    end
    for key, value in pairs(t1) do
    	if tableContains(t2, value) then return true end
    end

    for key, value in pairs(t2) do
        if tableContains(t1, value) then return true end
    end
    return false
end

local function findFishData(fishName)
	if type(fishName) == "table" then
	    for _, fish in ipairs(FishPondData) do
	    	local requiredTags = fish['RequiredTags'] or {}
	    	if requiredTags == {} then return nil end
	    	if (tablesEqual(fishName, requiredTags)) then return fish end
	    end
	    for _, fish in ipairs(FishPondData) do
	    	local requiredTags = fish['RequiredTags'] or {}
	    	if requiredTags == {} then return nil end
	    	if (tablesEqual2(fishName, requiredTags)) then return fish end
	    end
	    return nil
	end
	
    local lowerFishName = string.lower(fishName):gsub(" ", "")
    for _, fish in ipairs(FishPondData) do
        if string.lower(fish['Id']):gsub(" ", "") == lowerFishName then
            return fish
        end
    end
    return nil
end

-- =p.getMaxPopulation{ args = { "Lionfish"} }
function p.getMaxPopulation(frame)
    local fishName = frame.args[1]
    local id = ID.id {args = { fishName }}
    if id:sub(1, 3) == "(O)" then
        id = id:sub(4)
    else
        return ''
    end
    local name = Object.getFieldsById {args = { id }}["Name"]
    local fishData = findFishData(name)
    local tag
    if not fishData then
    	tag = Object.getAllFishTagById{args = {id}}
    	if tag then
    		fishData = findFishData(tag)
    	end
    	if not fishData then
        	return ''
        end
    end
    local result = -1
    if fishData then
    	result = fishData['MaxPopulation']
	end
    if tonumber(result) == -1 then
    	result = 10
	end
    return result or ''
end

-- =p.getSpawnTime{ args = { "Lionfish"} }
function p.getSpawnTime(frame)
    local fishName = frame.args[1]
    local id = ID.id {args = { fishName }}
    if id:sub(1, 3) == "(O)" then
        id = id:sub(4)
    else
        return ''
    end
    local name = Object.getFieldsById {args = { id }}["Name"]
    local fishData = findFishData(name)
    local tag
    if not fishData then
    	tag = Object.getAllFishTagById{args = {id}}
    	if tag then
    		fishData = findFishData(tag)
    	end
    	if not fishData then
        	return ''
        end
    end
    local result = fishData and fishData['SpawnTime'] or '-1'
    if tonumber(result) == -1 then
    	local id = ID.id {args = { fishName }}
    	if id:sub(1, 3) == "(O)" then
	        id = id:sub(4)
	    else
	        return -1
	    end
    	local price = Object.getPriceById {args = { id }}
    	if price <= 30 then
        	return 1
	    elseif price <= 80 then
	        return 2
	    elseif price <= 120 then
	        return 3
	    elseif price <= 250 then
	        return 4
	    else
	        return 5
	    end
    end
    return result
end

-- =p.getPopulationMissionCount{ args = { "Lionfish"} }
function p.getPopulationMissionCount(frame)
    local Gates = p.getPopulationGates(frame)
    if Gates ~= nil then
    	if #Gates <=0 then
    		return 0
		end
    	return #Gates
    end
	return ''
end

-- =p.getFishCount{ args = { "Lionfish"} }
function p.getFishCount(frame)
	local result = p.getMaxPopulation(frame)
	if tonumber(result) == 1 then return 1 end
    local Gates = p.getPopulationGates(frame)
    for _, k in pairs(Gates) do
    	if result > tonumber(k["Population"]) then result = tonumber(k["Population"]) end
    end
	if result < 2 then return 1 end
	return result-1
end

-- =p.getColor{ args = { "岩浆鳗鱼"} }
function p.getColor(frame)
	local totalCount = 0
    local fishName = frame.args[1]
    local id = ID.id {args = { fishName }}
    if id:sub(1, 3) == "(O)" then
        id = id:sub(4)
    else
        return ''
    end
    local name = Object.getFieldsById {args = { id }}["Name"]
    local fishData = findFishData(name)
    if not fishData or not fishData['WaterColor'] then
        return ''
    end
    local trueColor = ''
    local countRequired = 0
    local gateRequired = 0
    for _, k in pairs(fishData['WaterColor']) do
    	-- mw.logObject(k)
    	trueColor = k['Color']:gsub(" ", ", ")
    	countRequired = k['MinPopulation']
    	gateRequired = k['MinUnlockedPopulationGate']
    	totalCount = totalCount + 1
    end
    if totalCount ~= 1 then return '' end
    local first = ''
    if tonumber(gateRequired) == 2 then first = '完成首个任务,并且' end
    local ref = "(RGB 色值:".. trueColor ..")"
    return Helper.ExpandTemplate("模板:FishPonds/Color",{first, countRequired, trueColor, ref})
end

function p.getProducedItems(frame)
    local fishName = frame.args[1]
    local id = ID.id {args = { fishName }}
    if id:sub(1, 3) == "(O)" then
        id = id:sub(4)
    else
        return ''
    end
    local name = Object.getFieldsById {args = { id }}["Name"]
    local fishData = findFishData(name)
    local tag
    if not fishData or not fishData['ProducedItems'] then
    	tag = Object.getAllFishTagById{args = {id}}
    	if tag then
    		fishData = findFishData(tag)
    	end
    	if not fishData then
        	return ''
        end
    end

    
    local result = {}
    for _, item in ipairs(fishData['ProducedItems']) do
        table.insert(result, {
            RequiredPopulation = item['RequiredPopulation'],
            Chance = item['Chance'],
            Condition = item['Condition'],
            Id = item['Id'],
            MinStack = item['MinStack'],
            MaxStack = item['MaxStack']
        })
    end
    return result
end

function p.getPopulationGates(frame)
    local fishName = frame.args[1]
    local id = ID.id {args = { fishName }}
    if id:sub(1, 3) == "(O)" then
        id = id:sub(4)
    else
        return ''
    end
    local name = Object.getFieldsById {args = { id }}["Name"]
    local fishData = findFishData(name)
    local tag
    if not fishData or not fishData['PopulationGates'] then
    	tag = Object.getAllFishTagById{args = {id}}
    	if tag then
    		fishData = findFishData(tag)
    	end
    	if not fishData then
        	return ''
        end
    end
    
    local result = {}
    for population, gates in pairs(fishData['PopulationGates']) do
        table.insert(result, {
            Population = population,
            Gates = gates
        })
    end
    return result
end

-- =p.debug{ args = { "Lionfish"} }
function p.debug(frame)
    local fishName = frame.args[1]
    local output = {}
    output['MaxPopulation'] = p.getMaxPopulation(frame)
    output['SpawnTime'] = p.getSpawnTime(frame)
    output['ProducedItems'] = p.getProducedItems(frame)
    output['PopulationGates'] = p.getPopulationGates(frame)
    local result = {}
    for key, value in pairs(output) do
        if type(value) == 'table' then
            for _, item in ipairs(value) do
                table.insert(result, key .. ': ' .. mw.text.jsonEncode(item))
            end
        else
            table.insert(result, key .. ': ' .. tostring(value))
        end
    end
    return table.concat(result, '\n')
end

-- =p.getOpacityTable{ args = { "Lionfish"} }
function p.getOpacityTable(frame)
    local fishName = frame.args[1]
    local id = ID.id {args = { fishName }}
    if id:sub(1, 3) == "(O)" then
        id = id:sub(4)
    else
        return ''
    end
    local name = Object.getFieldsById {args = { id }}["Name"]
    local fishData = findFishData(name)
    local tag
    if not fishData or not fishData['PopulationGates'] then
    	tag = Object.getAllFishTagById{args = {id}}
    	if tag then
    		fishData = findFishData(tag)
    	end
    	if not fishData then
        	return ''
        end
    end
    -- local result = { Helper.ExpandTemplate("模板:FishPond/header") }
	local result = {}
    local maxPopulation = fishData['MaxPopulation'] or 11
    if tonumber(maxPopulation) == -1 then
    	maxPopulation = 11
    end
    local populationGates = fishData['PopulationGates']
	local sortedGates = {}
	if tag == "fish_legendary" then
		-- mw.logObject(fishData)
		-- mw.logObject(populationGates)
		return ''
	end
	for population, gates in pairs(populationGates) do
        table.insert(sortedGates, { Population = tonumber(population), Gates = gates })
	end
	table.sort(sortedGates, function(a, b) return a.Population < b.Population end)
    for i, gate in ipairs(sortedGates) do
        local population = gate.Population
        local nextPopulation = (i < #sortedGates) and sortedGates[i + 1].Population - 1 or tonumber(maxPopulation) - 1
        local items = {}
        for _, gateItem in ipairs(gate.Gates) do
            local item, quantity = gateItem:match("^(%S+) (%S+)%s*(%S*)$")

			if not item then
			    item = gateItem
			    quantity = 1
			elseif quantity == "" then
			    quantity = item
			    item = gateItem
			elseif quantity ~= "" and quantity:find("~") then
			    quantity = quantity
			end
            english = English.english{args = { item }}
            local sname = english:gsub(":", "")
            table.insert(items, Helper.ExpandTemplate("模板:Name",{sname, quantity, class = "inline"}))
        end
        local itemsString
        if #items == 1 then
            itemsString = items[1]
        elseif #items == 2 then
            itemsString = items[1] .. "或" .. items[2]
        else
            itemsString = table.concat(items, "、", 1, #items - 1) .. "或" .. items[#items]
        end
        local exp = 20 + p.getSpawnTime(frame) * 5
        table.insert(result, Helper.ExpandTemplate(
            "模板:FishPond/row",
            {
                old = population - 1,
                new = nextPopulation,
                item = itemsString,
                exp = exp
            }
        ))
    end
    -- table.insert(result, Helper.ExpandTemplate( "模板:FishPond/footer" ))
    return table.concat(result, "\n")
end

-- =p.getOpacityTableAlt{ args = { "Lionfish", "测试"} }
function p.getOpacityTableAlt(frame)
    local fishName = frame.args[1]
    local displayFishName = frame.args[2]
    local id = ID.id {args = { fishName }}
    if id:sub(1, 3) == "(O)" then
        id = id:sub(4)
    else
        return ''
    end
    local name = Object.getFieldsById {args = { id }}["Name"]
    local fishData = findFishData(name)
    local tag
    if not fishData or not fishData['PopulationGates'] then
    	tag = Object.getAllFishTagById{args = {id}}
    	if tag then
    		fishData = findFishData(tag)
    	end
    	if not fishData then
        	return ''
        end
    end
	local result = {}
    local maxPopulation = fishData['MaxPopulation'] or 11
    if tonumber(maxPopulation) == -1 then
    	maxPopulation = 11
    end
    local populationGates = fishData['PopulationGates']
	local sortedGates = {}
	if tag == "fish_legendary" then
		return ''
	end
	for population, gates in pairs(populationGates) do
        table.insert(sortedGates, { Population = tonumber(population), Gates = gates })
	end
	table.sort(sortedGates, function(a, b) return a.Population < b.Population end)
	local rowCount = #sortedGates
    for i, gate in ipairs(sortedGates) do
        local population = gate.Population
        local nextPopulation = (i < #sortedGates) and sortedGates[i + 1].Population - 1 or tonumber(maxPopulation) - 1
        local items = {}
        for _, gateItem in ipairs(gate.Gates) do
            local item, quantity = gateItem:match("^(%S+) (%S+)%s*(%S*)$")

			if not item then
			    item = gateItem
			    quantity = 1
			elseif quantity == "" then
			    quantity = item
			    item = gateItem
			elseif quantity ~= "" and quantity:find("~") then
			    quantity = quantity
			end
            english = English.english{args = { item }}
            local sname = english:gsub(":", "")
            table.insert(items, Helper.ExpandTemplate("模板:Name",{sname, quantity, class = "inline"}))
        end
        local itemsString
        if #items == 1 then
            itemsString = items[1]
        elseif #items == 2 then
            itemsString = items[1] .. "或" .. items[2]
        else
            itemsString = table.concat(items, "、", 1, #items - 1) .. "或" .. items[#items]
        end
        local spawnTime = p.getSpawnTime(frame)
        local exp = 20 + spawnTime * 5
        if displayFishName == "" or displayFishName == nil then
        	displayFishName = Helper.ExpandTemplate("模板:Name",{name, nil, class = "inline"})
        end
        
        if i == 1 then
	        table.insert(result, Helper.ExpandTemplate(
	            "模板:FishPond/row/alt",
	            {
	            	count = rowCount,
	            	fish = displayFishName,
	                before = population - 1,
	                after = nextPopulation,
	                item = itemsString,
	                interval = "每 ".. spawnTime .. " 天",
	                exp = exp
	            }
	        ))
        else
        	table.insert(result, Helper.ExpandTemplate(
	            "模板:FishPond/row/alt2",
	            {
	                before = population - 1,
	                after = nextPopulation,
	                item = itemsString
	            }
	        ))
    	end
    end
    return table.concat(result, "\n")
end

function toPercentage(number, disabled, multiplier, formatter)
	if number == "/" then return "/" end
	if number == "&nbsp;" then return "&nbsp;" end
	if number == "—" then return "—" end
	if multiplier == nil then multiplier = 100 end
	if formatter == nil then formatter = "%.1f" end -- %.2f
    local formatted = string.format(formatter, tonumber(number) * multiplier)
    formatted = formatted:gsub("%.00$", ""):gsub("%.0$", ""):gsub("%.([1-9])0$", ".%1")
    if disabled == true then
    	return formatted
	end
    return formatted .. "%"
end

local function deepcopy(original)
    local copy = {}
    for key, value in pairs(original) do
        if type(value) == "table" then
            copy[key] = deepcopy(value)  -- recursively copy nested tables
        else
            copy[key] = value
        end
    end
    return copy
end

function tableContains(table, element)
    for index, value in ipairs(table) do
        if value == element then
            return true
        end
    end
    return false
end

local function fileExists(filename)
    local title = mw.title.new("File:" .. filename)
    return title and title.exists
end

local function contains(text, substring)
    return string.find(text, substring, 1, true) ~= nil
end

-- =p.getProductTable{ args = { "午夜鱿鱼"} }
-- =p.getProductTable{ args = { "岩浆鳗鱼"} }
function p.getProductTable(frame)
    local fishName = frame.args[1]
    local id = ID.id { args = { fishName } }
    if id:sub(1, 3) == "(O)" then
        id = id:sub(4)
    else
        return ''
    end
    local name = Object.getFieldsById { args = { id } }["Name"]
    local EN = name
    local base_price = 30 + Object.getPriceById {args = { id }} * 0.5
    local promised_name = Object.getColorById{args = {id}} .. " Roe" or "Roe"
    if not fileExists(promised_name..".png") then
    	promised_name = "Roe"
	end

    local fishData = findFishData(name)
    local tag
    if not fishData or not fishData['ProducedItems'] then
        tag = Object.getAllFishTagById { args = { id } }
        if tag then
            fishData = findFishData(tag)
        end
        if not fishData then
            return ''
        end
    end
	if tag == "fish_legendary" then
        return ''
	end
	
    local maxPopulation = fishData['MaxPopulation'] or 11
    if maxPopulation == "-1" or maxPopulation == -1 then
        maxPopulation = 11
    end
    local producedItems = fishData['ProducedItems']
    local itemTable = {}
    local producesOrder = {}
    local sortedItems = {}
	for i, item in pairs(producedItems) do
		local item2 = deepcopy(item)
		item2["priority"] = i
        table.insert(sortedItems, { RequiredPopulation = tonumber(item.RequiredPopulation), Chance = item2.Chance, item = item2 })
    end
    table.sort(sortedItems, function(a, b) return a.RequiredPopulation < b.RequiredPopulation end)
	local lastUniqueId = ""
	local isZZZZ = false
    for i, item2 in pairs(sortedItems) do
    	local item = item2.item
        local population = item.RequiredPopulation > 0 and item.RequiredPopulation or 1
        local itemId = item.ItemId
        local cleanId
		if itemId:sub(1, 3) == "(O)" then
	        cleanId = itemId:sub(4)
		end
		local price = Object.getPriceById {args = { cleanId }}
		if cleanId == "812" then price = base_price end
		local experience = 10 + price * 0.04
		
        local english = English.english { args = { itemId } }
        local minStack = item.MinStack ~= -1 and item.MinStack or 1
        local maxStack = item.MaxStack ~= -1 and item.MaxStack or minStack
        local uniqueId = english .. "_" .. minStack .. "_" .. maxStack
        local quantityString = minStack == maxStack and tostring(minStack) or minStack .. "~" .. maxStack
		local priorityN = item.priority
		local sname = english:gsub(":", "")
        if not itemTable[uniqueId] then
            itemTable[uniqueId] = {
                item = Helper.ExpandTemplate("模板:Name", { sname, quantityString, class = "inline" }),
                requiredData = {},
                quantity = quantityString,
                priority = priorityN,
                experience = experience or 0
            }
            table.insert(producesOrder, uniqueId)
        end

        if population == 10 then
	        table.insert(itemTable[uniqueId].requiredData, {
	            rangeA = population,
	            rangeB = population,
                priority = priorityN
	        })
        else
        	table.insert(itemTable[uniqueId].requiredData, {
	            rangeA = population,
                priority = priorityN
	        })
        end
        local producesCount = #producesOrder
        
        if producesCount == 1 and item.Chance ~= 1 then
        	if itemTable['ZZZZ'] == nil then
	            itemTable['ZZZZ'] = {
	                item = '无',
	                requiredData = {},
	                quantity = quantityString,
	                priority = -1,
	                experience = "—"
	            }
        	end
        	local count = #itemTable['ZZZZ'].requiredData
        	if count~=0 then
        		local rangeB = itemTable['ZZZZ'].requiredData[count].rangeB
        		if rangeB == nil then itemTable['ZZZZ'].requiredData[count].rangeB = population - 1 end
        	end
        	table.insert(itemTable['ZZZZ'].requiredData, {
	            rangeA = population,
                priority = -1
	        })
	        isZZZZ = true
        end
        local tempProducesOrder = deepcopy(producesOrder)
        if isZZZZ == true then table.insert(tempProducesOrder, 'ZZZZ') end
	    for i, k in ipairs(tempProducesOrder) do
	    	local count = #itemTable[k].requiredData
	    	local priorityM = itemTable[k].requiredData[count].priority or nil
	    	if priorityM == nil then priorityM = -1 end
	    	if priorityM >= item.priority or k == "ZZZZ" then -- priorityM >= item.priority - 1
		    	local pop = population - 1
		    	local rangeA = itemTable[k].requiredData[count].rangeA
		    	local rangeB = itemTable[k].requiredData[count].rangeB
		    	if rangeA <= pop then
			    	local newChance = nil
					if rangeB == nil and rangeA <= pop then
						itemTable[k].requiredData[count].rangeB = pop
					end
					local newRangeB = nil
					if pop + 1 == 10 then newRangeB = 10 end
					if rangeB ~= 10 then
						table.insert(itemTable[k].requiredData, {
				            chance = newChance,
				            rangeA = pop + 1,
				            rangeB = newRangeB,
				            priority = priorityM
				        })
					end
		    	end
	    	end
	    end
        local count2 = #itemTable[uniqueId].requiredData - 1
        if count2 ~= 0 and itemTable[uniqueId].requiredData[count2].rangeB == nil then
        	itemTable[uniqueId].requiredData[count2].rangeB = population - 1
        end
    end
    if isZZZZ == true then table.insert(producesOrder, 'ZZZZ') end
    local producesCount = #producesOrder
    for _, k in ipairs(producesOrder) do
    	local v = itemTable[k]
    	local count3 = #itemTable[k].requiredData
    	if itemTable[k].requiredData[count3].rangeB == nil then
        	itemTable[k].requiredData[count3].rangeB = maxPopulation - 1
        end
    end
	local allValues = {}
	local producedItemsLength = 0
	local producedItems2 = deepcopy(producedItems)
	for i in pairs(producedItems2) do
	    producedItems2[i]["priority"] = i
	end
	for _ in pairs(producedItems2) do
	    producedItemsLength = producedItemsLength + 1
	end
	local lastRequired2 = -1
	local lastChance = -1
	local valuesDone = {}
	local common = {}
	local seen = {}
	for i = 1, producedItemsLength do
        local item = producedItems2[i]
        table.insert(common, item.RequiredPopulation)
	end
	local z = 1
	while z <= #common do
	    local value = common[z]
	    if seen[value] then
	        table.remove(common, z)
	    else
	        seen[value] = true
	        z = z + 1
	    end
	end
	table.sort(common, function(a, b) return a > b end)
	for startIndex = 1, producedItemsLength do
	    local values = {}
	    local probs = {}
	    local sum = 0
	    local currentRequiredPopulation = producedItems2[startIndex].RequiredPopulation
	    local currentPriority = producedItems2[startIndex].priority
	    if not tableContains(valuesDone, currentRequiredPopulation) or lastRequired2 == -1 then
	        lastRequired2 = currentRequiredPopulation
	        table.insert(valuesDone, currentRequiredPopulation)
	        local everTrue = false
	        for i = 1, producedItemsLength do
	            local item = producedItems2[i]
	            if currentRequiredPopulation >= item.RequiredPopulation and lastChance ~= 1 then
					lastChance = item.Chance
		            local prob = 1
		            for _, j in pairs(probs) do
		                prob = prob * (1 - j)
		            end
		            local itemId2 = item.ItemId
		            local english2 = English.english { args = { itemId2 } }
		            local minStack2 = item.MinStack ~= -1 and item.MinStack or 1
		            local maxStack2 = item.MaxStack ~= -1 and item.MaxStack or minStack2
		            local uniqueId2 = english2 .. "_" .. minStack2 .. "_" .. maxStack2
		            table.insert(probs, item.Chance)
		            local exactValue = prob * item.Chance * 100
		            if exactValue == 0 then
		                uniqueId2 = "ZZZZ"
		            end
		            table.insert(values,  {id = uniqueId2, prob = exactValue})
		            sum = sum + exactValue
	            end
	            if lastChance == 1 then
	            	lastChance = -1
	        	end
	        end
	        if sum <= 99 then
	            table.insert(values, {id = "ZZZZ", prob = 100 - sum})
	        end
			allValues[currentRequiredPopulation] = values
	    end
	end
	local allValuesTrue = {}
	for _, j in pairs(common) do
		table.insert(allValuesTrue, allValues[j])
	end
	allValues = allValuesTrue
	local mergedValues = {}
	for _, values in ipairs(allValues) do
	    local tempDict = {}
	    for _, value in ipairs(values) do
	        if tempDict[value.id] then
	            tempDict[value.id].prob = tempDict[value.id].prob + value.prob
	        else
	            tempDict[value.id] = {id = value.id, prob = value.prob}
	        end
	    end
	
	    local mergedLayer = {}
	    for _, mergedValue in pairs(tempDict) do
	        table.insert(mergedLayer, mergedValue)
	    end
	    table.insert(mergedValues, mergedLayer)
	end
	
	local finalMerged = {}
	for i = #mergedValues, 1, -1 do
	    local layer = mergedValues[i]
	    for _, item in ipairs(layer) do
	        local id = item.id
	        local prob = item.prob
	        if finalMerged[id] then
	            table.insert(finalMerged[id], 1, prob)
	        else
	            finalMerged[id] = {prob}
	        end
	    end
	end
    for i, k in ipairs(producesOrder) do
		local v = itemTable[k]
		local count3 = #itemTable[k].requiredData
		local counting2 = 1
		local test = {}
		local test2 = {}
		for _, x in pairs(finalMerged[k]) do
			if not tableContains(test2, x) then
				table.insert(test2, x)
				table.insert(test, x)
			end
		end
		for j = #test, 1, -1 do
			itemTable[k].requiredData[counting2]["probability"] = test[j]
			itemTable[k].requiredData[counting2]["priority"] = nil
			counting2 = counting2 + 1
		end
    end
    -- mw.logObject(itemTable)
    EN = EN:gsub(":", "")
    local itemDesc = Helper.ExpandTemplate("模板:Name",{EN, nil, class = "inline"}) or nil
    if contains(itemDesc, "Blank") then itemDesc = nil end
    local result = { Helper.ExpandTemplate("模板:FishPond2/header", { maxPopulation - 1, itemDesc } ) }
    
    for _, k in ipairs(producesOrder) do
    	local v = itemTable[k]
    	local count3 = #itemTable[k].requiredData
    	local counting2 = 1
    	local test = {}
		local test2 = {}
		local final = ""
		for _, x in pairs(finalMerged[k]) do
			if not tableContains(test2, x) then
				table.insert(test2, x)
				table.insert(test, x)
			end
		end
		local start = 1
		local startProb = 0
		local endCount = 10
		local endProb = 0
		local totalLength = 0
		local last1 = ''
		local last2 = ''
		local firstElement = v.item
		if contains(firstElement, "File:Roe.png") and promised_name ~= "Roe" then
			firstElement = firstElement:gsub("File:Roe.png", "File:" .. promised_name .. ".png")
		end
		local smallTable = {firstElement, k}
		for j = 1, #test do
			local x = itemTable[k].requiredData[counting2]
			if j == 1 then
				startProb = x.probability
			end
			if j == 1 and x.rangeA ~= 1 then
				start = x.rangeA
				local length2 = x.rangeA - 1
				totalLength = totalLength + length2
				local prob2 = "—" -- / 
				table.insert(smallTable, length2)
				table.insert(smallTable, toPercentage(prob2, false, 1))
				-- if final == "" then final = length2 else final = final .. "," .. length2 end
				-- final = final .. "," .. prob2
			end
			
			local length = x.rangeB - x.rangeA +1
			local prob = x.probability
			table.insert(smallTable, length)
			table.insert(smallTable, toPercentage(prob, false, 1))
			-- if final == "" then final = length else final = final .. "," .. length end
			-- final = final .. "," .. prob
			endCount = x.rangeB
			if x.probability ~= 0 then
				endProb = x.probability
			end
			counting2 = counting2 + 1
			if length == 0 then totalLength = totalLength + 1 end
			totalLength = totalLength + length
			
		end
		if totalLength ~= maxPopulation - 1 then
			local smallTableL = #smallTable
			if smallTableL >= 3 then
				-- mw.log(smallTable[smallTableL])
				if smallTable[smallTableL-1] == 0 then
					smallTable[smallTableL-1] = 2
				else
					if true then -- smallTable[smallTableL] == "0%"
						-- smallTable[smallTableL-1] = smallTable[smallTableL-1] + 1
						smallTable[smallTableL-1] = smallTable[smallTableL-1] + maxPopulation - 1 - totalLength
					else
						-- mw.log("maxPopulation - 1", maxPopulation - 1, "totalLength", totalLength)
						table.insert(smallTable, maxPopulation - 1 - totalLength)
						table.insert(smallTable, toPercentage(0))
					end
				end
				-- mw.log(smallTable[smallTableL-1],smallTable[smallTableL])
				-- if smallTable[smallTableL -1 ]
			end
		end
		-- mw.log(start, endCount)

		
		local cal1 = toPercentage((start * 0.08 + 0.15) * startProb / 100, true)
		local cal2 = toPercentage((endCount * 0.08 + 0.15) * endProb / 100, true)
		local calString = ""
		if cal1 == cal2 then
			calString = cal2 .. "%"
		else
			calString = cal1 .. " ~ " .. cal2 .. "%"
		end
		if k == "ZZZZ" then calString = "—" end
		table.insert(smallTable, calString)
		if v.experience == "—" then
			table.insert(smallTable, "—")
		else
			table.insert(smallTable, math.floor(v.experience))
		end
		final = table.concat(smallTable, ",")
		-- mw.log(final)
		table.insert(result, Helper.ExpandTemplate(
            "模板:FishPond2/row",
            {
                final
            }
        ))
	
    end
    table.insert(result,Helper.ExpandTemplate("模板:FishPond2/footer" ))
    return table.concat(result, "\n")
end

-- =p.getProductTableAlt{ args = { "岩浆鳗鱼"} }
function p.getProductTableAlt(frame)
    local fishName = frame.args[1]
    local displayFishName = frame.args[2]
    local id = ID.id { args = { fishName } }
    if id:sub(1, 3) == "(O)" then
        id = id:sub(4)
    else
        return ''
    end
    local name = Object.getFieldsById { args = { id } }["Name"]
    local EN = name
    local base_price = 30 + Object.getPriceById {args = { id }} * 0.5
    local promised_name = Object.getColorById{args = {id}} .. " Roe" or "Roe"
    if not fileExists(promised_name..".png") then
    	promised_name = "Roe"
	end

    local fishData = findFishData(name)
    local tag
    if not fishData or not fishData['ProducedItems'] then
        tag = Object.getAllFishTagById { args = { id } }
        if tag then
            fishData = findFishData(tag)
        end
        if not fishData then
            return ''
        end
    end
	if tag == "fish_legendary" then
        return ''
	end
	
    local maxPopulation = fishData['MaxPopulation'] or 11
    if maxPopulation == "-1" or maxPopulation == -1 then
        maxPopulation = 11
    end
    local producedItems = fishData['ProducedItems']
    local itemTable = {}
    local producesOrder = {}
    local sortedItems = {}
	for i, item in pairs(producedItems) do
		local item2 = deepcopy(item)
		item2["priority"] = i
        table.insert(sortedItems, { RequiredPopulation = tonumber(item.RequiredPopulation), Chance = item2.Chance, item = item2 })
    end
    table.sort(sortedItems, function(a, b) return a.RequiredPopulation < b.RequiredPopulation end)
	local lastUniqueId = ""
	local isZZZZ = false
    for i, item2 in pairs(sortedItems) do
    	local item = item2.item
        local population = item.RequiredPopulation > 0 and item.RequiredPopulation or 1
        local itemId = item.ItemId
        local cleanId
		if itemId:sub(1, 3) == "(O)" then
	        cleanId = itemId:sub(4)
		end
		local price = Object.getPriceById {args = { cleanId }}
		if cleanId == "812" then price = base_price end
		local experience = 10 + price * 0.04
		
        local english = English.english { args = { itemId } }
        local minStack = item.MinStack ~= -1 and item.MinStack or 1
        local maxStack = item.MaxStack ~= -1 and item.MaxStack or minStack
        local uniqueId = english .. "_" .. minStack .. "_" .. maxStack
        local quantityString = minStack == maxStack and tostring(minStack) or minStack .. "~" .. maxStack
		local priorityN = item.priority
		local sname = english:gsub(":", "")
        if not itemTable[uniqueId] then
            itemTable[uniqueId] = {
                item = Helper.ExpandTemplate("模板:Name", { sname, quantityString, class = "inline" }),
                requiredData = {},
                quantity = quantityString,
                priority = priorityN,
                experience = experience or 0
            }
            table.insert(producesOrder, uniqueId)
        end

        if population == 10 then
	        table.insert(itemTable[uniqueId].requiredData, {
	            rangeA = population,
	            rangeB = population,
                priority = priorityN
	        })
        else
        	table.insert(itemTable[uniqueId].requiredData, {
	            rangeA = population,
                priority = priorityN
	        })
        end
        local producesCount = #producesOrder
        
        if producesCount == 1 and item.Chance ~= 1 then
        	if itemTable['ZZZZ'] == nil then
	            itemTable['ZZZZ'] = {
	                item = '无',
	                requiredData = {},
	                quantity = quantityString,
	                priority = -1,
	                experience = "—"
	            }
        	end
        	local count = #itemTable['ZZZZ'].requiredData
        	if count~=0 then
        		local rangeB = itemTable['ZZZZ'].requiredData[count].rangeB
        		if rangeB == nil then itemTable['ZZZZ'].requiredData[count].rangeB = population - 1 end
        	end
        	table.insert(itemTable['ZZZZ'].requiredData, {
	            rangeA = population,
                priority = -1
	        })
	        isZZZZ = true
        end
        local tempProducesOrder = deepcopy(producesOrder)
        if isZZZZ == true then table.insert(tempProducesOrder, 'ZZZZ') end
	    for i, k in ipairs(tempProducesOrder) do
	    	local count = #itemTable[k].requiredData
	    	local priorityM = itemTable[k].requiredData[count].priority or nil
	    	if priorityM == nil then priorityM = -1 end
	    	if priorityM >= item.priority or k == "ZZZZ" then -- priorityM >= item.priority - 1
		    	local pop = population - 1
		    	local rangeA = itemTable[k].requiredData[count].rangeA
		    	local rangeB = itemTable[k].requiredData[count].rangeB
		    	if rangeA <= pop then
			    	local newChance = nil
					if rangeB == nil and rangeA <= pop then
						itemTable[k].requiredData[count].rangeB = pop
					end
					local newRangeB = nil
					if pop + 1 == 10 then newRangeB = 10 end
					if rangeB ~= 10 then
						table.insert(itemTable[k].requiredData, {
				            chance = newChance,
				            rangeA = pop + 1,
				            rangeB = newRangeB,
				            priority = priorityM
				        })
					end
		    	end
	    	end
	    end
        local count2 = #itemTable[uniqueId].requiredData - 1
        if count2 ~= 0 and itemTable[uniqueId].requiredData[count2].rangeB == nil then
        	itemTable[uniqueId].requiredData[count2].rangeB = population - 1
        end
    end
    if isZZZZ == true then table.insert(producesOrder, 'ZZZZ') end
    local producesCount = #producesOrder
    for _, k in ipairs(producesOrder) do
    	local v = itemTable[k]
    	local count3 = #itemTable[k].requiredData
    	if itemTable[k].requiredData[count3].rangeB == nil then
        	itemTable[k].requiredData[count3].rangeB = maxPopulation - 1
        end
    end
	local allValues = {}
	local producedItemsLength = 0
	local producedItems2 = deepcopy(producedItems)
	for i in pairs(producedItems2) do
	    producedItems2[i]["priority"] = i
	end
	for _ in pairs(producedItems2) do
	    producedItemsLength = producedItemsLength + 1
	end
	local lastRequired2 = -1
	local lastChance = -1
	local valuesDone = {}
	local common = {}
	local seen = {}
	local result = {}
	for i = 1, producedItemsLength do
        local item = producedItems2[i]
        table.insert(common, item.RequiredPopulation)
	end
	local z = 1
	while z <= #common do
	    local value = common[z]
	    if seen[value] then
	        table.remove(common, z)
	    else
	        seen[value] = true
	        z = z + 1
	    end
	end
	table.sort(common, function(a, b) return a > b end)
	for startIndex = 1, producedItemsLength do
	    local values = {}
	    local probs = {}
	    local sum = 0
	    local currentRequiredPopulation = producedItems2[startIndex].RequiredPopulation
	    local currentPriority = producedItems2[startIndex].priority
	    if not tableContains(valuesDone, currentRequiredPopulation) or lastRequired2 == -1 then
	        lastRequired2 = currentRequiredPopulation
	        table.insert(valuesDone, currentRequiredPopulation)
	        local everTrue = false
	        for i = 1, producedItemsLength do
	            local item = producedItems2[i]
	            if currentRequiredPopulation >= item.RequiredPopulation and lastChance ~= 1 then
					lastChance = item.Chance
		            local prob = 1
		            for _, j in pairs(probs) do
		                prob = prob * (1 - j)
		            end
		            local itemId2 = item.ItemId
		            local english2 = English.english { args = { itemId2 } }
		            local minStack2 = item.MinStack ~= -1 and item.MinStack or 1
		            local maxStack2 = item.MaxStack ~= -1 and item.MaxStack or minStack2
		            local uniqueId2 = english2 .. "_" .. minStack2 .. "_" .. maxStack2
		            table.insert(probs, item.Chance)
		            local exactValue = prob * item.Chance * 100
		            if exactValue == 0 then
		                uniqueId2 = "ZZZZ"
		            end
		            table.insert(values,  {id = uniqueId2, prob = exactValue})
		            sum = sum + exactValue
	            end
	            if lastChance == 1 then
	            	lastChance = -1
	        	end
	        end
	        if sum <= 99 then
	            table.insert(values, {id = "ZZZZ", prob = 100 - sum})
	        end
			allValues[currentRequiredPopulation] = values
	    end
	end
	local allValuesTrue = {}
	for _, j in pairs(common) do
		table.insert(allValuesTrue, allValues[j])
	end
	allValues = allValuesTrue
	local mergedValues = {}
	for _, values in ipairs(allValues) do
	    local tempDict = {}
	    for _, value in ipairs(values) do
	        if tempDict[value.id] then
	            tempDict[value.id].prob = tempDict[value.id].prob + value.prob
	        else
	            tempDict[value.id] = {id = value.id, prob = value.prob}
	        end
	    end
	
	    local mergedLayer = {}
	    for _, mergedValue in pairs(tempDict) do
	        table.insert(mergedLayer, mergedValue)
	    end
	    table.insert(mergedValues, mergedLayer)
	end
	
	local finalMerged = {}
	for i = #mergedValues, 1, -1 do
	    local layer = mergedValues[i]
	    for _, item in ipairs(layer) do
	        local id = item.id
	        local prob = item.prob
	        if finalMerged[id] then
	            table.insert(finalMerged[id], 1, prob)
	        else
	            finalMerged[id] = {prob}
	        end
	    end
	end
    for i, k in ipairs(producesOrder) do
		local v = itemTable[k]
		local count3 = #itemTable[k].requiredData
		local counting2 = 1
		local test = {}
		local test2 = {}
		for _, x in pairs(finalMerged[k]) do
			if not tableContains(test2, x) then
				table.insert(test2, x)
				table.insert(test, x)
			end
		end
		for j = #test, 1, -1 do
			itemTable[k].requiredData[counting2]["probability"] = test[j]
			itemTable[k].requiredData[counting2]["priority"] = nil
			counting2 = counting2 + 1
		end
    end
    -- mw.logObject(itemTable)
    EN = EN:gsub(":", "")
    local itemDesc = Helper.ExpandTemplate("模板:Name",{EN, nil, class = "inline"}) or nil
    if contains(itemDesc, "Blank") then itemDesc = nil end
    
    for sim, k in ipairs(producesOrder) do
    	local v = itemTable[k]
    	local count3 = #itemTable[k].requiredData
    	local counting2 = 1
    	local test = {}
		local test2 = {}
		local final = ""
		for _, x in pairs(finalMerged[k]) do
			if not tableContains(test2, x) then
				table.insert(test2, x)
				table.insert(test, x)
			end
		end
		local start = 1
		local startProb = 0
		local endCount = 10
		local endProb = 0
		local totalLength = 0
		local last1 = ''
		local last2 = ''
		local firstElement = v.item
		if contains(firstElement, "File:Roe.png") and promised_name ~= "Roe" then
			firstElement = firstElement:gsub("File:Roe.png", "File:" .. promised_name .. ".png")
		end
		local smallTable = {firstElement, k}
		for j = 1, #test do
			local x = itemTable[k].requiredData[counting2]
			if j == 1 then
				startProb = x.probability
			end
			if j == 1 and x.rangeA ~= 1 then
				start = x.rangeA
				local length2 = x.rangeA - 1
				totalLength = totalLength + length2
				local prob2 = "—" -- / 
				table.insert(smallTable, length2)
				table.insert(smallTable, toPercentage(prob2, false, 1))
				-- if final == "" then final = length2 else final = final .. "," .. length2 end
				-- final = final .. "," .. prob2
			end
			
			local length = x.rangeB - x.rangeA +1
			local prob = x.probability
			table.insert(smallTable, length)
			table.insert(smallTable, toPercentage(prob, false, 1))
			-- if final == "" then final = length else final = final .. "," .. length end
			-- final = final .. "," .. prob
			endCount = x.rangeB
			if x.probability ~= 0 then
				endProb = x.probability
			end
			counting2 = counting2 + 1
			if length == 0 then totalLength = totalLength + 1 end
			totalLength = totalLength + length
			
		end
		if totalLength ~= maxPopulation - 1 then
			local smallTableL = #smallTable
			if smallTableL >= 3 then
				-- mw.log(smallTable[smallTableL])
				if smallTable[smallTableL-1] == 0 then
					smallTable[smallTableL-1] = 2
				else
					if true then -- smallTable[smallTableL] == "0%"
						-- smallTable[smallTableL-1] = smallTable[smallTableL-1] + 1
						smallTable[smallTableL-1] = smallTable[smallTableL-1] + maxPopulation - 1 - totalLength
					else
						-- mw.log("maxPopulation - 1", maxPopulation - 1, "totalLength", totalLength)
						table.insert(smallTable, maxPopulation - 1 - totalLength)
						table.insert(smallTable, toPercentage(0))
					end
				end
				-- mw.log(smallTable[smallTableL-1],smallTable[smallTableL])
				-- if smallTable[smallTableL -1 ]
			end
		end
		-- mw.log(start, endCount)

		
		local cal1 = toPercentage((start * 0.08 + 0.15) * startProb / 100, true)
		local cal2 = toPercentage((endCount * 0.08 + 0.15) * endProb / 100, true)
		local calString = ""
		if cal1 == cal2 then
			calString = cal2 .. "%"
		else
			calString = cal1 .. " ~ " .. cal2 .. "%"
		end
		if k == "ZZZZ" then calString = "—" end
		table.insert(smallTable, calString)
		if v.experience == "—" then
			table.insert(smallTable, "—")
		else
			table.insert(smallTable, math.floor(v.experience))
		end
		final = table.concat(smallTable, ",")
		-- mw.log(final)
		local insertContent = Helper.ExpandTemplate(
            "模板:FishPond2/row",
            {
                final
            })
        if sim == 1 then
        	if displayFishName == "" or displayFishName == nil then
        		displayFishName = Helper.ExpandTemplate("模板:Name",{name, nil, class = "inline"})
        	end
			insertContent = insertContent:gsub('<tr><td data', '<tr><td rowspan="'.. #producesOrder ..'">' .. displayFishName .. '</td><td data')
    	end
		table.insert(result, insertContent)
	
    end
    return table.concat(result, "\n")
end

return p