Module:RecipeLoader: Difference between revisions

From Evospace
Jump to navigation Jump to search
No edit summary
No edit summary
 
(27 intermediate revisions by the same user not shown)
Line 1: Line 1:
local p = {}
local p = {}


-- Функция вывода одной таблицы для рецепта
local function normalizeArray(tbl)
    local result = {}
    if not tbl then return result end
    for k, v in pairs(tbl) do
        if type(v) == "table" then
            local name = v[1] or v.name or v["1"]
            local count = v[2] or v.count or v["2"] or 1
            table.insert(result, {name, count})
        end
    end
    table.sort(result, function(a,b) return tostring(a[1]) < tostring(b[1]) end)
    return result
end
 
local function splitCamelCase(str)
    str = str:gsub("_", " ")
    str = str:gsub("(%l)(%u)", "%1 %2")
    str = str:gsub("(%a)(%d)", "%1 %2")
    str = str:gsub("(%d)(%a)", "%1 %2")
    return str
end
 
local function firstExistingIcon(machine)
    local nsFile = mw.site.namespaces.File.id
    local candidates = {
        string.format("T_%s.png", machine),
        string.format("T_Stone%s.png", machine),
        string.format("T_Copper%s.png", machine),
        string.format("T_Steel%s.png", machine),
        string.format("T_Aluminium%s.png", machine),
        string.format("T_StainlessSteel%s.png", machine),
        string.format("T_Titanium%s.png", machine),
        string.format("T_Composite%s.png", machine),
        string.format("T_Neutronium%s.png", machine),
    }
 
    for _, filename in ipairs(candidates) do
        local title = mw.title.makeTitle(nsFile, filename)
        if title and title.exists then
            return filename
        end
    end
 
    return nil -- ничего не найдено
end
 
local function renderRecipeInput(recipe)
    local inputs = normalizeArray(recipe.input)
    local str = ''
 
    if #inputs > 0 then
        for _, ing in ipairs(inputs) do
            str = str ..
                "|-\n| " ..
                string.format("[[File:T_%s.png|22px]]", ing[1]) ..
                string.format("[[%s]] × %s", splitCamelCase(ing[1]), tostring(ing[2])) ..
                "\n"
        end
    else
        str = str .. "—"
    end
 
    return str
end
 
local function renderRecipe(recipe)
local function renderRecipe(recipe)
    local inputs = normalizeArray(recipe.input)
    local outputs = normalizeArray(recipe.output)
    local ticks = recipe.ticks or recipe.time or ""
    local machine = recipe.machine or recipe.made_in or recipe.crafter or nil
     local tableNode = mw.html.create("table")
     local tableNode = mw.html.create("table")
         :addClass("wikitable recipe-table")
         :addClass("recipe-table")
        :css("text-align", "left")
        :css("margin-bottom", "15px")
        :css("min-width", "300px")


     -- ===== input =====
     -- Заголовок: только машина, без fallback
     tableNode:tag("tr")
     local caption = tableNode:tag("caption")
         :tag("th"):attr("colspan", 3):wikitext("Input"):done()
 
         :done()
    if machine then
         local icon = firstExistingIcon(machine)
 
        if icon then
            caption:wikitext(string.format(
                "[[File:%s|20px]] [[%s]]",
                icon,
                splitCamelCase(machine)
            ))
        else
            caption:wikitext(splitCamelCase(machine)) -- если иконки нет, показываем только текст
         end
    else
        caption:wikitext("") -- пустой
    end


     if recipe.input and #recipe.input > 0 then
    -- Input
         for _, ing in ipairs(recipe.input) do
    tableNode:tag("tr"):tag("th"):attr("colspan", 2):wikitext("Input")
     if #inputs > 0 then
         for _, ing in ipairs(inputs) do
             local tr = tableNode:tag("tr")
             local tr = tableNode:tag("tr")
             tr:tag("td"):wikitext(string.format("[[File:T_%s.png|32px]]", ing[1])):done()
             tr:tag("td"):wikitext(string.format("[[File:T_%s.png|22px]]", ing[1]))
             tr:tag("td"):wikitext(string.format("[[%s]]", ing[1])):done()
             tr:tag("td"):wikitext(string.format("[[%s]] × %s",
            tr:tag("td"):wikitext("× " .. tostring(ing[2])):done()
                splitCamelCase(ing[1]),
                tostring(ing[2])))
         end
         end
     else
     else
         tableNode:tag("tr")
         tableNode:tag("tr"):tag("td"):attr("colspan", 2):wikitext("—")
            :tag("td"):attr("colspan", 3):wikitext("—"):done()
     end
     end


     -- ===== Output =====
     -- Output
     tableNode:tag("tr")
     tableNode:tag("tr"):tag("th"):attr("colspan", 2):wikitext("Output")
        :tag("th"):attr("colspan", 3):wikitext("Output"):done()
     if #outputs > 0 then
        :done()
         for _, res in ipairs(outputs) do
 
     if recipe.output and #recipe.output > 0 then
         for _, res in ipairs(recipe.output) do
             local tr = tableNode:tag("tr")
             local tr = tableNode:tag("tr")
             tr:tag("td"):wikitext(string.format("[[File:T_%s.png|32px]]", res[1])):done()
             tr:tag("td"):wikitext(string.format("[[File:T_%s.png|22px]]", res[1]))
             tr:tag("td"):wikitext(string.format("[[%s]]", res[1])):done()
             tr:tag("td"):wikitext(string.format("[[%s]] × %s",
            tr:tag("td"):wikitext("× " .. tostring(res[2])):done()
                splitCamelCase(res[1]),
                tostring(res[2])))
         end
         end
     else
     else
         tableNode:tag("tr")
         tableNode:tag("tr"):tag("td"):attr("colspan", 2):wikitext("—")
            :tag("td"):attr("colspan", 3):wikitext("—"):done()
     end
     end


     -- ===== Time =====
     -- Time
    tableNode:tag("tr"):tag("th"):attr("colspan", 2):wikitext("Time")
     tableNode:tag("tr")
     tableNode:tag("tr")
         :tag("th"):attr("colspan", 3):wikitext("Time"):done()
         :tag("td"):attr("colspan", 2)
        :done()
        :css("text-align", "center")
    tableNode:tag("tr")
         :wikitext(tostring(ticks/20.0) .. " sec")
         :tag("td"):attr("colspan", 3):wikitext(tostring(recipe.time or "") .. " ticks"):done()


     return tableNode
     return tableNode
end
end


 
function p.getInput(frame)
-- Вывод одного конкретного рецепта
function p.get(frame)
     local dictName = frame.args[1]
     local dictName = frame.args[1]
    local recipeName = frame.args[2]
     if not dictName then return "❌ Missing parameter: dictName" end
 
     if not dictName or not recipeName then
        return "❌ Missing parameters: {{Recipe|DictionaryName|RecipeName}}"
    end


     local success, recipes = pcall(mw.loadData, "Module:" .. dictName)
     local success, recipes = pcall(mw.loadData, "Module:" .. dictName)
     if not success or type(recipes) ~= "table" then
     if not success or type(recipes) ~= "table" then return "" end
        return "❌ Recipe dictionary not found: " .. tostring(dictName)
    end


     local html = mw.html.create()
     return renderRecipeInput(recipes[1])
    for _, recipe in ipairs(recipes) do
        if recipe.name == recipeName then
            html:node(renderRecipe(recipe))
        end
    end
 
    if tostring(html) == "" then
        return "⚠️ Recipe not found: " .. tostring(recipeName)
    end
 
    return tostring(html)
end
end


-- Вывод всех рецептов из словаря
function p.getAll(frame)
function p.getAll(frame)
     local dictName = frame.args[1]
     local dictName = frame.args[1]
 
     if not dictName then return "❌ Missing parameter: dictName" end
     if not dictName then
        return "❌ Missing parameter: {{AllRecipes|DictionaryName}}"
    end


     local success, recipes = pcall(mw.loadData, "Module:" .. dictName)
     local success, recipes = pcall(mw.loadData, "Module:" .. dictName)
     if not success or type(recipes) ~= "table" then
     if not success or type(recipes) ~= "table" then return "" end
        return "❌ Recipe dictionary not found: " .. tostring(dictName)
    end


     local html = mw.html.create()
     local html = mw.html.create()


     for _, recipe in ipairs(recipes) do
     for _, recipe in ipairs(recipes) do
        html:tag("h4"):wikitext(recipe.name or "(no name)"):done()
         html:node(renderRecipe(recipe))
         html:node(renderRecipe(recipe))
     end
     end

Latest revision as of 11:01, 30 October 2025

Documentation for this module may be created at Module:RecipeLoader/doc

local p = {}

local function normalizeArray(tbl)
    local result = {}
    if not tbl then return result end
    for k, v in pairs(tbl) do
        if type(v) == "table" then
            local name = v[1] or v.name or v["1"]
            local count = v[2] or v.count or v["2"] or 1
            table.insert(result, {name, count})
        end
    end
    table.sort(result, function(a,b) return tostring(a[1]) < tostring(b[1]) end)
    return result
end

local function splitCamelCase(str)
    str = str:gsub("_", " ")
    str = str:gsub("(%l)(%u)", "%1 %2")
    str = str:gsub("(%a)(%d)", "%1 %2")
    str = str:gsub("(%d)(%a)", "%1 %2")
    return str
end

local function firstExistingIcon(machine)
    local nsFile = mw.site.namespaces.File.id
    local candidates = {
        string.format("T_%s.png", machine),
        string.format("T_Stone%s.png", machine),
        string.format("T_Copper%s.png", machine),
        string.format("T_Steel%s.png", machine),
        string.format("T_Aluminium%s.png", machine),
        string.format("T_StainlessSteel%s.png", machine),
        string.format("T_Titanium%s.png", machine),
        string.format("T_Composite%s.png", machine),
        string.format("T_Neutronium%s.png", machine),
    }

    for _, filename in ipairs(candidates) do
        local title = mw.title.makeTitle(nsFile, filename)
        if title and title.exists then
            return filename
        end
    end

    return nil -- ничего не найдено
end

local function renderRecipeInput(recipe)
    local inputs = normalizeArray(recipe.input)
    local str = ''

    if #inputs > 0 then
        for _, ing in ipairs(inputs) do
            str = str ..
                "|-\n| " ..
                string.format("[[File:T_%s.png|22px]]", ing[1]) ..
                string.format("[[%s]] × %s", splitCamelCase(ing[1]), tostring(ing[2])) ..
                "\n"
        end
    else
        str = str .. "—"
    end

    return str
end

local function renderRecipe(recipe)
    local inputs = normalizeArray(recipe.input)
    local outputs = normalizeArray(recipe.output)
    local ticks = recipe.ticks or recipe.time or ""
    local machine = recipe.machine or recipe.made_in or recipe.crafter or nil

    local tableNode = mw.html.create("table")
        :addClass("recipe-table")

    -- Заголовок: только машина, без fallback
    local caption = tableNode:tag("caption")

    if machine then
        local icon = firstExistingIcon(machine)

        if icon then
            caption:wikitext(string.format(
                "[[File:%s|20px]] [[%s]]",
                icon,
                splitCamelCase(machine)
            ))
        else
            caption:wikitext(splitCamelCase(machine)) -- если иконки нет, показываем только текст
        end
    else
        caption:wikitext("") -- пустой
    end

    -- Input
    tableNode:tag("tr"):tag("th"):attr("colspan", 2):wikitext("Input")
    if #inputs > 0 then
        for _, ing in ipairs(inputs) do
            local tr = tableNode:tag("tr")
            tr:tag("td"):wikitext(string.format("[[File:T_%s.png|22px]]", ing[1]))
            tr:tag("td"):wikitext(string.format("[[%s]] × %s",
                splitCamelCase(ing[1]),
                tostring(ing[2])))
        end
    else
        tableNode:tag("tr"):tag("td"):attr("colspan", 2):wikitext("—")
    end

    -- Output
    tableNode:tag("tr"):tag("th"):attr("colspan", 2):wikitext("Output")
    if #outputs > 0 then
        for _, res in ipairs(outputs) do
            local tr = tableNode:tag("tr")
            tr:tag("td"):wikitext(string.format("[[File:T_%s.png|22px]]", res[1]))
            tr:tag("td"):wikitext(string.format("[[%s]] × %s",
                splitCamelCase(res[1]),
                tostring(res[2])))
        end
    else
        tableNode:tag("tr"):tag("td"):attr("colspan", 2):wikitext("—")
    end

    -- Time
    tableNode:tag("tr"):tag("th"):attr("colspan", 2):wikitext("Time")
    tableNode:tag("tr")
        :tag("td"):attr("colspan", 2)
        :css("text-align", "center")
        :wikitext(tostring(ticks/20.0) .. " sec")

    return tableNode
end

function p.getInput(frame)
    local dictName = frame.args[1]
    if not dictName then return "❌ Missing parameter: dictName" end

    local success, recipes = pcall(mw.loadData, "Module:" .. dictName)
    if not success or type(recipes) ~= "table" then return "" end

    return renderRecipeInput(recipes[1])
end

function p.getAll(frame)
    local dictName = frame.args[1]
    if not dictName then return "❌ Missing parameter: dictName" end

    local success, recipes = pcall(mw.loadData, "Module:" .. dictName)
    if not success or type(recipes) ~= "table" then return "" end

    local html = mw.html.create()

    for _, recipe in ipairs(recipes) do
        html:node(renderRecipe(recipe))
    end

    return tostring(html)
end

return p