- 欢迎光临Satisfactory国区BWIKI。请登录您的B站账号,方可使用页面编辑与评论功能。

全站通知:

模块:RenderCraftingRecipesTable

来自幸福工厂WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

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

local cargo = mw.ext.cargo
local moduleTooltips = require('Module:ItemTooltip')

local p = {}
local buildings = {}
local experimental_style = 'position:absolute; font-variant:all-small-caps; font-size:small; font-weight:bold; left:0; top:0; transform: rotate(-45deg) translate(-15px, -5px); background:red; color:white; padding: 1px 20px;'
local unreleased_style = 'position: absolute; font-variant: all-small-caps; font-size: smaller; left: 0; width: 100%; font-weight: bold; background: repeating-linear-gradient( -45deg, yellow, yellow 8px, black 8px, black 16px); color: black; text-shadow: -1px -1px 0 #fff, -1px 1px 0 #fff, 1px -1px 0 #fff, 1px 1px 0 #fff; padding-bottom: 2px;'

local function loadBuildingsPower()
  local tables = 'buildings'
  local fields = 'name, powerUsage'
  local args = { where = 'powerUsage > 0' }
  local result = cargo.query(tables, fields, args)
  
  buildings = {}
  for _, building in pairs(result) do
    buildings[building.name] = tonumber(building.powerUsage)
  end
end

local function round(num, numDecimalPlaces)
  local mult = 10^(numDecimalPlaces or 0)
  return math.floor(num * mult + 0.5) / mult
end

local function generateRecipeTableRow(recipe, useItemTooltips)
  local html = ''
  
  -- fix some parameters
  recipe.alternateRecipe = (tonumber(recipe.alternateRecipe) or 0) > 0
  recipe.inCraftBench = (tonumber(recipe.inCraftBench) or 0) > 0
  recipe.inWorkShop = (tonumber(recipe.inWorkShop) or 0) > 0
  recipe.craftingTime = tonumber(recipe.craftingTime) or 0
  if recipe.craftedIn == nil or #tostring(recipe.craftedIn) <= 1 then -- <=1 instead of ==0 just in case of \n or single space characters; normally craftedIn is a long word
    if recipe.inWorkShop then
      recipe.craftedIn = 'Equipment Workshop'
    elseif recipe.inCraftBench then
      recipe.craftedIn = 'Craft Bench'
    else
      recipe.craftedIn = 'Build Gun'
    end
  end
  
  -- split ingredients and products from recipe into separate arrays
  local ingredients = {}
  for i=1, 9, 1 do
    local item = recipe["ingredient" .. i]
    if item ~= nil and #item > 0 then
      ingredients[i] = { name = item, amount = tonumber(recipe["quantity" .. i]) or 1 }
    end
  end

  local products = {}
  for i=1, 4, 1 do
    local item = recipe["product" .. i]
    if item ~= nil and #item > 0 then
      products[i] = { name = item, amount = tonumber(recipe["productCount" .. i]) or 1 }
    end
  end
  
  -- calculations for table cells
  local ingredientsCols = #ingredients <= 1 and 1 or math.max(2, math.ceil(#ingredients/2))
  local ingredientsRows = math.ceil(#ingredients/ingredientsCols)
  local ingredientsColspan = 12 / ingredientsCols -- ingredients column is 12 columns wide (with colspan) to be divisible by 1, 2, 3 or 4
  
  local productsCols = #products <= 1 and 1 or math.max(2, math.ceil(#products/2))
  local productsRows = math.ceil(#products/productsCols)
  local productsColspan = 2 / productsCols
  
  local maxRows = math.max(ingredientsRows, productsRows)
  local ingredientsRowspan = maxRows / ingredientsRows
  local productsRowspan = maxRows / productsRows
    
  local ingredientCells = {}
  local productCells = {}
  
  -- function generates HTML for ingredients/products cells and stores generated code in targetTable array
  local function generateCells(list, rowspan, colspan, targetTable, addEnergyPerItem)
    for i=1, #list, 1 do
      local td = '<td style="border:0; line-height:1; padding:0.5em" rowspan="' .. rowspan .. '" colspan="' .. colspan .. '">'
      local ipm = 60 / recipe.craftingTime * list[i].amount
      
      if useItemTooltips then
  		--td = td .. mw.getCurrentFrame():expandTemplate{title = 'ItemTooltip', args = { list[i].name, list[i].amount }}
  		td = td .. moduleTooltips.getTooltip{ args = { item = list[i].name, amount = list[i].amount, size = 40 } }
  	  else
	    td = td .. '<div style="line-height:1"><div style="font-size:medium; display:inline-table">' .. list[i].amount .. ' × [[Image:' .. list[i].name .. '.png|40px|link=' .. list[i].name .. ']]</br>'
	    td = td .. '<div style="font-size:x-small; text-align:right">' .. list[i].name .. '</div></div></div>'
      end
	  
      if recipe.craftingTime > 0 then
        td = td .. '<div style="font-weight:bold; line-height:2">' .. ipm .. ' / min</div>'
        
        -- calculate energy per item
        if addEnergyPerItem then
          buildingPower = buildings[recipe.craftedIn]
          if buildingPower ~= nil then
            local displayText = round(recipe.craftingTime * buildingPower / list[i].amount, 2) .. ' MJ / item'
            local tooltipText = 'The energy consumed by ' .. recipe.craftedIn .. ' to craft 1 item at 100% clock'
            td = td .. '<div style="font-size:x-small; line-height:1; border:solid 1px cornflowerblue; border-radius:0.5em; background-color:aliceblue; padding:0.08em 0.4em; display:inline">' .. mw.getCurrentFrame():expandTemplate{title='Tooltip', args={[1]=displayText, [2]=tooltipText, [3]='no underline'}} .. '</div>'
          end
        end
      else
        -- if no craftingTime and no ipm to display then add some empty block for proper spacing
        td = td .. '<div style="font-weight:bold; line-height:2">&nbsp;</div>'
      end
      td = td .. '</td>'
      targetTable[i] = td
    end
    -- odd amount of ingredients/products leaves one empty cell in the column, which should be filled by a blank cell
    -- also generate one empty cell when there's no ingredients/products at all
    if #list == 0 or #list > 1 and #list % 2 == 1 then
      targetTable[#targetTable+1] = '<td style="border:0" rowspan="' .. rowspan .. '" colspan="' .. colspan .. '">&nbsp;</td>'
    end
  end
  
  -- generate all ingredients and products cells
  generateCells(ingredients, ingredientsRowspan, ingredientsColspan, ingredientCells)
  generateCells(products, productsRowspan, productsColspan, productCells, true) -- for products add energy per item
    
  -- assemble the table
  for i=1, maxRows, 1 do
    -- recipe name column
    if i == 1 then
      recipeName = recipe.recipeName
      if (recipeName == Null or recipeName == '') then recipeName = recipe.product1 end
      if (recipeName == Null or recipeName == '') then recipeName = 'Not specified' end
      if recipe.alternateRecipe then 
        recipeName = recipeName .. '</br>' .. '<span style="text-transform:uppercase; font-size:x-small; background-color:cornsilk; padding:0.1em 0.4em; border-radius:0;border:solid 1px orange">[[Hard Drive|Alternate]]</span>'
      end
      local stripe = ''
      if recipe.experimental == '1' then
      	stripe = '<div style="' .. experimental_style .. '">' 
      			 .. mw.getCurrentFrame():expandTemplate{title='Tooltip', args={[1]='Exp', [2]='This recipe is available only in Experimental version of Satisfactory', [3]='no underline'}}
      			 .. '</div>'
  	  elseif recipe.unreleased == '1' then
  	  	stripe = '<div style="' .. unreleased_style .. ' top:0;">'
  	  			 .. mw.getCurrentFrame():expandTemplate{title='Tooltip', args={[1]='Unreleased', [2]='This recipe is not obtainable ingame. It was either datamined or removed from the game.', [3]='no underline'}}
      			 .. '</div>'
      			 .. '<div style="' .. unreleased_style .. ' bottom:0;">&nbsp;</div>'
  	  end
      html = html 
             .. '<tr class="firstRow" style="border-top: 2px solid #575757">' 
             .. '<td rowspan="' .. maxRows .. '" style="line-height:1; position:relative; overflow:hidden;">' 
        	.. recipeName 
        	.. stripe
        	.. '</td>'
    else
      html = html .. '<tr>'
    end
    
    -- ingredients column
    for j=1, ingredientsCols, 1 do
      local index = (i-1)*ingredientsCols+j
      if index <= #ingredientCells then
        html = html .. ingredientCells[index]
      end
    end
    
    -- building column
    if i == 1 then
      html = html .. '<td rowspan="' .. maxRows .. '"><span  style="font-size:large">[[' .. recipe.craftedIn .. ']]</span>'
      if recipe.craftingTime > 0 then
        html = html .. '</br>' .. recipe.craftingTime .. ' sec'
      end
      if recipe.inCraftBench or recipe.inWorkShop then
        local displayText = '[[File:Manual crafting.png|16px]] × ' .. recipe.craftingClicks
        local tooltipText = 'Manual crafting speed : ' .. 240 / (tonumber(recipe.craftingClicks) or 0) * (tonumber(recipe.productCount1) or 1) .. ' / min'
        html = html ..'</br>' .. mw.getCurrentFrame():expandTemplate{title='Tooltip', args={[1]=displayText, [2]=tooltipText, [3]='no underline'}} 
      end
      html = html .. '</td>'
    end
    
    -- products column
    for j=1, productsCols, 1 do
      local index = (i-1)*productsCols+j
      if index <= #productCells then
        html = html .. productCells[index]
      end
    end
    
    -- prerequisites column
    if i == 1 then
      html = html .. '<td rowspan="' .. maxRows .. '"><span style="text-align:left;">' .. recipe.researchTier .. '</span></td>'
    end
    
    html = html .. '</tr>'
  end
  
  return html
end

local fields = 'recipeName, alternateRecipe, mainRecipe, craftedIn, inCraftBench, inWorkShop, craftingTime, craftingClicks, researchTier, unreleased, experimental, product=product1, product2, product3, product4, productCount=productCount1, productCount2, productCount3, productCount4, ingredient1, quantity1, ingredient2, quantity2, ingredient3, quantity3, ingredient4, quantity4, ingredient5, quantity5, ingredient6, quantity6, ingredient7, quantity7, ingredient8, quantity8'

local function generateTable(recipes, useItemTooltips)  
  local html = '<table class="wikitable" style="text-align:center"><tr><th>Recipe</th><th colspan="12">Ingredients</th><th>Building</th><th colspan="2">Products</th><th>Prerequisites</th></tr>'
  
  for i=1, #recipes, 1 do
    html = html .. generateRecipeTableRow(recipes[i], useItemTooltips)
  end
  
  html = html .. '</table>'
  return html
end

function p.generateCraftingRecipes(frame)
  local itemName = frame.args.item or frame.args[1]
  local useItemTooltips = frame.args.tooltips and (#frame.args.tooltips > 0) or false
  local experimental = frame.args.experimental and (#frame.args.experimental > 0) or false
  local experimentalCondition = experimental and ' and (experimental=True)' or ' and (experimental is null or experimental=False)'
  
  local tables = 'crafting_recipes'
  local args = { where = '(product="' .. itemName .. '" or product2="' .. itemName .. '" or product3="' .. itemName .. '" or product4="' .. itemName .. '")' .. experimentalCondition, 
                 orderBy = 'mainRecipe DESC, alternateRecipe ASC' }
  local recipes = cargo.query(tables, fields, args)
  
  if #recipes > 0 then
    loadBuildingsPower()
    return generateTable(recipes, useItemTooltips)
  else
    return "'''" .. itemName .. "''' can't be crafted."
  end
end

function p.generateCraftingUsage(frame)
  local itemName = frame.args.item or frame.args[1]
  local useItemTooltips = frame.args.tooltips and (#frame.args.tooltips > 0) or false
  local experimental = frame.args.experimental and (#frame.args.experimental > 0) or false
  local unreleased = frame.args.unreleased and (#frame.args.unreleased > 0) or false
  
  local experimentalCondition = experimental and ' and (experimental=True)' or ' and (experimental is null or experimental=False)'
  local unreleasedCondition = unreleased and '' or ' and (unreleased is null or unreleased=False)'
  
  local tables = 'crafting_recipes'
  local args = { where = 'product IS NOT NULL and _pageName NOT LIKE "%/%" and (ingredient1="' .. itemName .. '" or ingredient2="' .. itemName .. '" or ingredient3="' .. itemName .. '" or ingredient4="' .. itemName .. '" or ingredient5="' .. itemName .. '" or ingredient6="' .. itemName .. '" or ingredient7="' .. itemName .. '" or ingredient8="' .. itemName .. '" or ingredient9="' .. itemName .. '" or ingredient10="' .. itemName .. '")' .. experimentalCondition .. unreleasedCondition, 
                 orderBy = '(craftedIn IS NOT NULL or inWorkShop or inCraftBench) DESC, product ASC, alternateRecipe ASC' }
  local recipes = cargo.query(tables, fields, args)
  
  if #recipes > 0 then
    loadBuildingsPower()
    return generateTable(recipes, useItemTooltips)
  else
    return "'''" .. itemName .. "''' isn't used to craft anything."
  end
end

return p