Module:TechRecipe: Difference between revisions

From Desynced Wiki
No edit summary
No edit summary
Line 71: Line 71:
     for _, f in ipairs(numericFields) do
     for _, f in ipairs(numericFields) do
         row[f] = tonumber(row[f]) or 0
         row[f] = tonumber(row[f]) or 0
    end
    if row.numProduced == 0 then
        row.numProduced = 1
     end
     end


Line 85: Line 88:
     local ing = tech["ingredient" .. i]
     local ing = tech["ingredient" .. i]
     ---@type integer
     ---@type integer
     local amt = (tech["amount" .. i]) * (multiply or 1)
     local amt = (tech["amount" .. i]) * multiply


     if not ing or ing == "" then
     if not ing or ing == "" then
Line 122: Line 125:
     local dataRow = recipeTable:tag("tr")
     local dataRow = recipeTable:tag("tr")
     for i = 1, 4 do
     for i = 1, 4 do
         local row = m.ingredient_cell(tech, i, 1)
         local row = m.ingredient_cell(tech, i, multiply)
         if row then
         if row then
             dataRow:node(row[1])
             dataRow:node(row[1])
Line 162: Line 165:


     m.table_header(table, tech)
     m.table_header(table, tech)
     m.ingredients_row(table, tech, tech.progressCount)
     m.ingredients_row(table, tech, tech.progressCount) -- / could be round_up(tech.progressCount / tech.numProduced), but numProduced seems to be always 1
     return tostring(table)
     return tostring(table)
end
end
Line 190: Line 193:
--[[
--[[
Debugging:
Debugging:
Return m instead of p if you want to debug those private functions


local frame = { args = { name = "Ultra-tech Framework" } }
local frame = { args = { name = "Ultra-tech Framework" } }

Revision as of 00:35, 12 August 2025

Description

The recipe part of the tech pages.

If new research components are added to the game, UPLINK_REPLACEMENTS needs be extended to enable replacing the component with the related building. Otherwise it will just show the new component instead.

Usage

Example {{#invoke:TechRecipe|render|name=<techName>}}

Example

The following call:
{{#invoke:TechRecipe|render|name=Ultra-tech Framework}}

Results in:

Recipe
Fused ElectrodesIC ChipRobotics ResearchUltra-tech Framework
Fused Electrodes 1IC Chip 1Robotics Research 3Arrow RightUltra-tech Framework
Produced by
Total Requirements
Fused ElectrodesIC ChipRobotics ResearchUltra-tech Framework
Fused Electrodes 20IC Chip 20Robotics Research 60Arrow RightUltra-tech Framework

local p = {}
local m = {} -- you can use this one for debugging without exposing functions, return this instead of p

---@type any
---@diagnostic disable-next-line: lowercase-global
mw = mw

-- Mirror tech cargo table
---@class TechCargo
---@field name string
---@field luaId string
---@field description string
---@field category string
---@field texture string
---@field requiredTech1 string
---@field requiredTech2 string
---@field requiredTech3 string
---@field progressCount integer
---@field ingredient1 string
---@field amount1 integer
---@field ingredient2 string
---@field amount2 integer
---@field ingredient3 string
---@field amount3 integer
---@field ingredient4 string
---@field amount4 integer
---@field producer1 string
---@field time1 number
---@field producer2 string
---@field time2 number
---@field producer3 string
---@field time3 number
---@field producer4 string
---@field time4 number
---@field recipeType string
---@field numProduced integer

---@param name string
function m.get_tech_cargo_data(name)
local fields = "name, luaId, description, category, texture, " ..
                   "requiredTech1, requiredTech2, requiredTech3, " ..
                   "progressCount, " ..
                   "ingredient1, amount1, " ..
                   "ingredient2, amount2, " ..
                   "ingredient3, amount3, " ..
                   "ingredient4, amount4, " ..
                   "producer1, time1, " ..
                   "producer2, time2, " ..
                   "producer3, time3, " ..
                   "producer4, time4, " ..
                   "recipeType, numProduced"

    local results = mw.ext.cargo.query(
        "tech",                    -- table name
        fields,                    -- fields list
        { where = string.format("name = '%s'", name) }
    )
    
    if not results or not results[1] then
        return nil
    end

    local row = results[1]

    local numericFields = {
        "progressCount",
        "amount1", "amount2", "amount3", "amount4",
        "time1", "time2", "time3", "time4",
        "numProduced"
    }
    for _, f in ipairs(numericFields) do
        row[f] = tonumber(row[f]) or 0
    end
    if row.numProduced == 0 then
        row.numProduced = 1
    end

    ---@cast row TechCargo
    return row
end

-- Helper: creates a table cell for an ingredient
---@param tech TechCargo The tech cargo object
---@param i integer Ingredient index (1–4)
---@param multiply integer Amount multiplier
---@return table|nil An html <td> element or nil if no ingredient
m.ingredient_cell =  function(tech, i, multiply)
    local ing = tech["ingredient" .. i]
    ---@type integer
    local amt = (tech["amount" .. i]) * multiply

    if not ing or ing == "" then
        return nil
    end

    return {
        mw.html.create("td")
            :wikitext(string.format(
                "[[File:%s.png|64x64px|link=%s|alt=%s]] %i",
                ing, ing, ing, amt
            ))
    }
end

-- Insert a 6 cells header
---@param recipeTable table
---@param tech TechCargo
m.table_header = function(recipeTable, tech)
    local headerRow = recipeTable:tag("tr")
    for i = 1, 4 do
        if tech["ingredient"..i] and tech["ingredient"..i] ~= "" then
            headerRow:tag("th"):wikitext(string.format("[[%s]]", tech["ingredient"..i])):done()
        end
    end
    -- Empty cell, for arrow under it
    headerRow:tag("th"):done()
    headerRow:tag("th"):wikitext(tech.name):done()
end

-- Insert a 6 cells row
---@param recipeTable table
---@param tech TechCargo
---@param multiply integer Multiply all counts by this
m.ingredients_row = function(recipeTable, tech, multiply)
    local dataRow = recipeTable:tag("tr")
    for i = 1, 4 do
        local row = m.ingredient_cell(tech, i, multiply)
        if row then
            dataRow:node(row[1])
        end
    end
    dataRow:tag("td"):wikitext("[[File:Arrow_Right.png|link=Arrow Right|alt=Arrow Right|32x32px]]"):done()
    dataRow:tag("td"):wikitext(string.format("[[File:%s.png|64x64px|link=Technology/%s|alt=%s]]",
        tech.name, tech.name, tech.name)):done()
end

---@param tech TechCargo
m.recipe_table = function(tech)
    local table = mw.html.create("table")
    table
        :addClass("wikitable")
        :tag("caption"):wikitext("Recipe"):done()

    m.table_header(table, tech)
    m.ingredients_row(table, tech, 1)
    return tostring(table)
end

---@param tech TechCargo
m.produced_by_table = function(tech)
    local table = mw.html.create("table")
    table
        :addClass("wikitable")
        :tag("caption"):wikitext("Produced by"):done()

    return tostring(table)
end

---@param tech TechCargo
m.total_requirements_table = function(tech)
    local table = mw.html.create("table")
    table
        :addClass("wikitable")
        :tag("caption"):wikitext("Total Requirements"):done()

    m.table_header(table, tech)
    m.ingredients_row(table, tech, tech.progressCount) -- / could be round_up(tech.progressCount / tech.numProduced), but numProduced seems to be always 1
    return tostring(table)
end

--- Main function
---@param name string
m.render = function(name)
    local tech = m.get_tech_cargo_data(name)
    if not tech then
        return "(Recipe not found)"
    end

    local result = 
          m.recipe_table(tech)
      ..  m.produced_by_table(tech)
      ..  m.total_requirements_table(tech)

    return result
end

p.render = function (frame)
    return m.render(frame.args.name)
end

return p

--[[
Debugging:

Return m instead of p if you want to debug those private functions

local frame = { args = { name = "Ultra-tech Framework" } }
(enter)
= p.render(frame)
(enter)

--]]