Модуль:Песочница/Pok: различия между версиями

Нет описания правки
Нет описания правки
Строка 1: Строка 1:
-- Загрузка данных
local p = {}
local latheData = mw.loadData("Модуль:IanComradeBot/prototypes/lathe.json/data") -- Данные станков
 
local recipeData = mw.loadData("Модуль:IanComradeBot/prototypes/lathe/recipes.json/data") -- Данные рецептов
-----------------------------
local researchData = mw.loadData("Модуль:IanComradeBot/prototypes/research.json/data") -- Данные исследований
-- Функция для «очистки» JSON
local materialData = mw.loadData("Модуль:IanComradeBot/prototypes/materials.json/data") -- Данные материалов
-----------------------------
local chemData = mw.loadData("Модуль:IanComradeBot/chem prototypes.json/data") -- Данные химических веществ
local function cleanJSON(json)
    -- Удаляем запятую перед закрывающей квадратной скобкой (конец массива)
    json = json:gsub(",%s*%]", "]")
    -- Удаляем запятую перед закрывающей фигурной скобкой (конец объекта)
    json = json:gsub(",%s*%}", "}")
    return json
end


local p = {}
---------------------------------------------
-- Функция для загрузки и парсинга JSON-файла
---------------------------------------------
local function loadJSONData(pageName)
    local title = mw.title.new(pageName)
    if not title then
        return {}
    end
    local jsonData = title:getContent() or ""
    jsonData = cleanJSON(jsonData)
    local success, data = pcall(mw.text.jsonDecode, jsonData)
    if success and type(data) == "table" then
        return data
    else
        return {}
    end
end
 
-----------------------------------------------------------
-- Загрузка данных: заменяем mw.loadData на loadJSONData()
-----------------------------------------------------------
local latheData    = loadJSONData("User:IanComradeBot/prototypes/lathe.json")
local recipeData  = loadJSONData("User:IanComradeBot/prototypes/lathe/recipes.json")
local researchData = loadJSONData("User:IanComradeBot/prototypes/research.json")
local materialData = loadJSONData("User:IanComradeBot/prototypes/materials.json")
local chemData    = loadJSONData("User:IanComradeBot/chem prototypes.json")


-----------------------------------------------------------
-- Функция для форматирования времени
-- Функция для форматирования времени
-----------------------------------------------------------
local function format_seconds_to_short_string(input_seconds)
local function format_seconds_to_short_string(input_seconds)
local minutes = math.floor(input_seconds / 60)
    local minutes = math.floor(input_seconds / 60)
local seconds = input_seconds % 60
    local seconds = input_seconds % 60


local minutes_part = minutes > 0 and (minutes .. " мин.") or nil
    local minutes_part = minutes > 0 and (minutes .. " мин.") or nil
local seconds_part = seconds > 0 and (seconds .. " сек.") or nil
    local seconds_part = seconds > 0 and (seconds .. " сек.") or nil


if minutes_part and seconds_part then
    if minutes_part and seconds_part then
return minutes_part .. " " .. seconds_part
        return minutes_part .. " " .. seconds_part
elseif seconds_part then
    elseif seconds_part then
return seconds_part
        return seconds_part
elseif minutes_part then
    elseif minutes_part then
return minutes_part
        return minutes_part
else
    else
return '0 сек.'
        return '0 сек.'
end
    end
end
end


-----------------------------------------------------------
-- Функция для сортировки рецептов
-- Функция для сортировки рецептов
-----------------------------------------------------------
local function sortRecipesByPriority(recipes)
local function sortRecipesByPriority(recipes)
table.sort(recipes, function(a, b)
    table.sort(recipes, function(a, b)
local priority = { Static = 1, EMAG = 3 }
        local priority = { Static = 1, EMAG = 3 }
local aPriority = priority[a.discipline] or 2
        local aPriority = priority[a.discipline] or 2
local bPriority = priority[b.discipline] or 2
        local bPriority = priority[b.discipline] or 2


if a.isEmag ~= b.isEmag then
        if a.isEmag ~= b.isEmag then
return not a.isEmag
            return not a.isEmag
end
        end


if aPriority == bPriority then
        if aPriority == bPriority then
if a.tier == b.tier then
            if a.tier == b.tier then
return a.discipline < b.discipline
                return a.discipline < b.discipline
end
            end
return a.tier < b.tier
            return a.tier < b.tier
end
        end


return aPriority < bPriority
        return aPriority < bPriority
end)
    end)
end
end


-----------------------------------------------------------
-- Основная функция модуля
-----------------------------------------------------------
function p.main(frame)
function p.main(frame)
-- Подключение CSS
    -- Подключение CSS
local cssLink = frame:extensionTag('templatestyles', '', {
    local cssLink = frame:extensionTag('templatestyles', '', {
src = 'Шаблон:Prototypes/Машина/Станок/styles.css'
        src = 'Шаблон:Prototypes/Машина/Станок/styles.css'
})
    })
 
local latheId = frame.args[1] or ""
if latheId == "" then
return '<div style="color:red;">Не указан ID станка.</div>'
end


local lathe = nil
    local latheId = frame.args[1] or ""
for _, data in ipairs(latheData) do
    if latheId == "" then
if data.id == latheId then
        return '<div style="color:red;">Не указан ID станка.</div>'
lathe = data
    end
break
end
end


if not lathe then
    local lathe = nil
return '<div style="color:red;">Станок с ID "' .. latheId .. '" не найден.</div>'
    for _, data in ipairs(latheData) do
end
        if data.id == latheId then
            lathe = data
            break
        end
    end


-- Построение сопоставления материалов по их ID
    if not lathe then
local materialMapping = {}
        return '<div style="color:red;">Станок с ID "' .. latheId .. '" не найден.</div>'
for _, material in ipairs(materialData) do
    end
    if material.id then
        materialMapping[material.id] = material.stackEntity or material.id or material.name
    end
end


-- Построение сопоставления химии
    local materialMapping = {}
local chemMapping = {}
    for _, material in ipairs(materialData) do
for id, chem in pairs(chemData) do
        if material.id then
chemMapping[id] = chem.name
            materialMapping[material.id] = material.stackEntity or material.id or material.name
end
        end
    end


local out = cssLink
    local chemMapping = {}
local recipes = {}
    for id, chem in pairs(chemData) do
        chemMapping[id] = chem.name
    end


local function getRecipeDetails(recipeId)
    local out = cssLink
    for _, recipe in ipairs(recipeData) do
    local recipes = {}
        if recipe.id == recipeId then
            return recipe
        end
    end
    return nil
end


local function findInResearch(recipeId)
    local function getRecipeDetails(recipeId)
for _, research in ipairs(researchData) do
        for _, recipe in ipairs(recipeData) do
if research.technology and research.technology.recipeUnlocks then
            if recipe.id == recipeId then
for _, unlock in ipairs(research.technology.recipeUnlocks) do
                return recipe
if unlock == recipeId then
            end
return {
        end
name = research.technology.name,
        return nil
tier = research.technology.tier,
    end
discipline = research.technology.discipline
}
end
end
end
end
return nil
end


-- Обработка staticRecipes
    local function findInResearch(recipeId)
if lathe.Lathe and lathe.Lathe.staticRecipes then
        for _, research in ipairs(researchData) do
for _, recipeId in ipairs(lathe.Lathe.staticRecipes) do
            if research.technology and research.technology.recipeUnlocks then
local recipe = getRecipeDetails(recipeId)
                for _, unlock in ipairs(research.technology.recipeUnlocks) do
if recipe and recipe.result then
                    if unlock == recipeId then
table.insert(recipes, {
                        return {
result = recipe.result,
                            name = research.technology.name,
completetime = recipe.completetime,
                            tier = research.technology.tier,
materials = recipe.materials,
                            discipline = research.technology.discipline
discipline = "Static",
                        }
tier = 0
                    end
})
                end
elseif recipe and recipe.resultReagents then
            end
    for reagent, amount in pairs(recipe.resultReagents) do
        end
        local reagentName = chemMapping[reagent] or reagent
        return nil
        table.insert(recipes, {
    end
            result = reagentName .. "|amount=" .. amount .. "ед.|mode-chem=1",
            completetime = recipe.completetime,
            materials = recipe.materials,
            discipline = "Static",
            tier = 0
        })
        break
    end
else
out = out .. '<div style="color:red;">Ошибка: Рецепт с ID "' .. recipeId .. '" не найден или поля result/resultReagents отсутствуют.</div>'
end
end
end


-- Обработка dynamicRecipes
    -- Обработка staticRecipes
if lathe.Lathe and lathe.Lathe.dynamicRecipes then
    if lathe.Lathe and lathe.Lathe.staticRecipes then
for _, recipeId in ipairs(lathe.Lathe.dynamicRecipes) do
        for _, recipeId in ipairs(lathe.Lathe.staticRecipes) do
local recipe = getRecipeDetails(recipeId)
            local recipe = getRecipeDetails(recipeId)
if recipe then
            if recipe and recipe.result then
local researchInfo = findInResearch(recipeId)
                table.insert(recipes, {
if researchInfo then
                    result = recipe.result,
table.insert(recipes, {
                    completetime = recipe.completetime,
result = recipe.result,
                    materials = recipe.materials,
completetime = recipe.completetime,
                    discipline = "Static",
materials = recipe.materials,
                    tier = 0
discipline = researchInfo.discipline,
                })
tier = researchInfo.tier,
            elseif recipe and recipe.resultReagents then
researchName = researchInfo.name
                for reagent, amount in pairs(recipe.resultReagents) do
})
                    local reagentName = chemMapping[reagent] or reagent
end
                    table.insert(recipes, {
end
                        result = reagentName .. "|amount=" .. amount .. "ед.|mode-chem=1",
end
                        completetime = recipe.completetime,
end
                        materials = recipe.materials,
                        discipline = "Static",
                        tier = 0
                    })
                    break
                end
            else
                out = out .. '<div style="color:red;">Ошибка: Рецепт с ID "' .. recipeId .. '" не найден или поля result/resultReagents отсутствуют.</div>'
            end
        end
    end


-- Обработка emagStaticRecipes
    -- Обработка dynamicRecipes
if lathe.EmagLatheRecipes and lathe.EmagLatheRecipes.emagStaticRecipes then
    if lathe.Lathe and lathe.Lathe.dynamicRecipes then
for _, recipeId in ipairs(lathe.EmagLatheRecipes.emagStaticRecipes) do
        for _, recipeId in ipairs(lathe.Lathe.dynamicRecipes) do
local recipe = getRecipeDetails(recipeId)
            local recipe = getRecipeDetails(recipeId)
if recipe then
            if recipe then
table.insert(recipes, {
                local researchInfo = findInResearch(recipeId)
result = recipe.result,
                if researchInfo then
completetime = recipe.completetime,
                    table.insert(recipes, {
materials = recipe.materials,
                        result = recipe.result,
discipline = "Static",
                        completetime = recipe.completetime,
tier = 0,
                        materials = recipe.materials,
isEmag = true
                        discipline = researchInfo.discipline,
})
                        tier = researchInfo.tier,
end
                        researchName = researchInfo.name
end
                    })
end
                end
            end
        end
    end


-- Обработка emagDynamicRecipes
    -- Обработка emagStaticRecipes
if lathe.EmagLatheRecipes and lathe.EmagLatheRecipes.emagDynamicRecipes then
    if lathe.EmagLatheRecipes and lathe.EmagLatheRecipes.emagStaticRecipes then
for _, recipeId in ipairs(lathe.EmagLatheRecipes.emagDynamicRecipes) do
        for _, recipeId in ipairs(lathe.EmagLatheRecipes.emagStaticRecipes) do
local recipe = getRecipeDetails(recipeId)
            local recipe = getRecipeDetails(recipeId)
if recipe then
            if recipe then
local researchInfo = findInResearch(recipeId)
                table.insert(recipes, {
if researchInfo then
                    result = recipe.result,
table.insert(recipes, {
                    completetime = recipe.completetime,
result = recipe.result,
                    materials = recipe.materials,
completetime = recipe.completetime,
                    discipline = "Static",
materials = recipe.materials,
                    tier = 0,
discipline = researchInfo.discipline,
                    isEmag = true
tier = researchInfo.tier,
                })
researchName = researchInfo.name,
            end
isEmag = true
        end
})
    end
end
end
end
end


sortRecipesByPriority(recipes)
    -- Обработка emagDynamicRecipes
    if lathe.EmagLatheRecipes and lathe.EmagLatheRecipes.emagDynamicRecipes then
        for _, recipeId in ipairs(lathe.EmagLatheRecipes.emagDynamicRecipes) do
            local recipe = getRecipeDetails(recipeId)
            if recipe then
                local researchInfo = findInResearch(recipeId)
                if researchInfo then
                    table.insert(recipes, {
                        result = recipe.result,
                        completetime = recipe.completetime,
                        materials = recipe.materials,
                        discipline = researchInfo.discipline,
                        tier = researchInfo.tier,
                        researchName = researchInfo.name,
                        isEmag = true
                    })
                end
            end
        end
    end


-- Таблица для перевода названий дисциплин
    sortRecipesByPriority(recipes)
local disciplineMapping = {
Arsenal = "Арсенал",
Industrial = "Промышленность",
Experimental = "Экспериментальное",
CivilianServices = "Обслуживание персонала"
}


-- Таблица для цветов по уровням
    -- Таблица для перевода названий дисциплин
local tierColors = {
    local disciplineMapping = {
[1] = "#54d554",
        Arsenal = "Арсенал",
[2] = "#ed9000",
        Industrial = "Промышленность",
[3] = "#d72a2a"
        Experimental = "Экспериментальное",
}
        CivilianServices = "Обслуживание персонала"
    }


local materialUseMultiplier = lathe.Lathe and lathe.Lathe.materialUseMultiplier or 1
    -- Таблица для цветов по уровням
local timeMultiplier = lathe.Lathe and lathe.Lathe.timeMultiplier or 1
    local tierColors = {
        [1] = "#54d554",
        [2] = "#ed9000",
        [3] = "#d72a2a"
    }


for _, recipe in ipairs(recipes) do
    local materialUseMultiplier = (lathe.Lathe and lathe.Lathe.materialUseMultiplier) or 1
local scaledTime = format_seconds_to_short_string(recipe.completetime * timeMultiplier)
    local timeMultiplier = (lathe.Lathe and lathe.Lathe.timeMultiplier) or 1
out = out .. '{{Шаблон:Prototypes/Машина/Станок|product=' .. recipe.result
out = out .. '|complete-time=' .. scaledTime
out = out .. '|materials='


-- Если данные по материалам могут прийти как строка, попробуем декодировать
    for _, recipe in ipairs(recipes) do
local matData = recipe.materials
        local scaledTime = format_seconds_to_short_string(recipe.completetime * timeMultiplier)
if type(matData) == "string" then
        out = out .. '{{Шаблон:Prototypes/Машина/Станок|product=' .. recipe.result
local ok, decoded = pcall(mw.text.jsonDecode, matData)
        out = out .. '|complete-time=' .. scaledTime
if ok and type(decoded) == "table" then
        out = out .. '|materials='
matData = decoded
end
end


if type(matData) == "table" and next(matData) then
        if type(recipe.materials) == "table" and next(recipe.materials) then
for material, amount in pairs(matData) do
            for material, amount in pairs(recipe.materials) do
local stackEntity = materialMapping[material] or material
                local stackEntity = materialMapping[material] or material
-- Применяем множитель и масштабируем количество
                local scaledAmount = (amount * materialUseMultiplier) / 100
local scaledAmount = (amount * materialUseMultiplier) / 100
                out = out .. '<b>[[File:' .. stackEntity .. '.png|32x32px|link=]] ' .. scaledAmount .. ' {{#invoke:Entity Lookup|getname|' .. stackEntity .. '}}</b>'
out = out .. '<b>[[File:' .. stackEntity .. '.png|32x32px|link=]] ' .. scaledAmount .. ' {{#invoke:Entity Lookup|getname|' .. stackEntity .. '}}</b> '
            end
end
        else
else
            out = out .. 'Нет данных о материалах'
out = out .. 'Нет данных о материалах'
        end
end


-- Информация об исследовании
        -- Информация об исследовании
if recipe.discipline ~= "Static" then
        if recipe.discipline ~= "Static" then
local tierColor = tierColors[recipe.tier] or "#FFFFFF"
            local tierColor = tierColors[recipe.tier] or "#FFFFFF"
local disciplineName = disciplineMapping[recipe.discipline] or "Неизвестная дисциплина"
            local disciplineName = disciplineMapping[recipe.discipline] or "Неизвестная дисциплина"


out = out .. '|info=<div style="font-weight:600;"><span style="margin:8px;">[[File:' .. recipe.discipline .. '.png|16x16px|link=]]</span> [[Руководство по исследованию и разработке|' .. disciplineName
            out = out .. '|info=<div style="font-weight:600;"><span style="margin:8px;">[[File:' .. recipe.discipline .. '.png|16x16px|link=]]</span> [[Руководство по исследованию и разработке|' .. disciplineName
out = out .. ']], уровень: <span style="color: ' .. tierColor .. '">' .. recipe.tier .. '</span> </div>'
            out = out .. ']], уровень: <span style="color: ' .. tierColor .. '">' .. recipe.tier .. '</span> </div>'
end
        end


-- Пометка при взломе EMAG
        -- Пометка при взломе EMAG
if recipe.isEmag then
        if recipe.isEmag then
out = out .. '|mode-emag=1'
            out = out .. '|mode-emag=1'
end
        end


-- Пометка для исследуемой технологии
        -- Пометка для исследуемой технологии
if recipe.discipline ~= "Static" then
        if recipe.discipline ~= "Static" then
out = out .. '|mode-research=1'
            out = out .. '|mode-research=1'
end
        end


out = out .. '}}'
        out = out .. '}}'
end
    end


return mw.getCurrentFrame():preprocess(out)
    return mw.getCurrentFrame():preprocess(out)
end
end


return p
return p