Модуль:Chemistry Lookup

Материал из FIRE STATION WIKI

Для документации этого модуля может быть создана страница Модуль:Chemistry Lookup/doc

local loader = require("Module:JsonPageLoader")

-- Загружаем данные из JSON файлов
local chem_data = loader.load("User:FireBot/chem_prototypes.json")
local react_data = loader.load("User:FireBot/react_prototypes.json") 
local status_data = loader.load("User:FireBot/chem_status.json")

local p = {}

-- Основные данные
p.chem = chem_data
p.react = react_data
p.status = status_data

-- Направления групп для навигации
p.groupDirection = {
    Drinks = "Drinks",
    Foods = "Cooking",
}

-- Функция для чтения скалярного значения из химических данных
function p.readscalar(frame)
    local chem_id = frame.args[1]
    local property = frame.args[2]
    
    if p.chem[chem_id] and p.chem[chem_id][property] then
        return mw.text.nowiki(tostring(p.chem[chem_id][property]))
    end
    return ""
end

-- Функция для чтения скалярного значения из данных реакций
function p.readscalarreact(frame)
    local react_id = frame.args[1]
    local property = frame.args[2]
    
    if p.react[react_id] and p.react[react_id][property] then
        return mw.text.nowiki(tostring(p.react[react_id][property]))
    end
    return ""
end

-- Получение цвета химического вещества
function p.getcolor(frame)
    local chem_id = frame.args[1]
    
    if p.chem[chem_id] and p.chem[chem_id].color then
        local color = p.chem[chem_id].color
        -- Обрезаем до 7 символов (#RRGGBB)
        return mw.text.nowiki(color:sub(1, 7))
    end
    return "#FFFFFF"
end

-- Получение цвета текста на основе яркости фона
function p.gettextcolor(frame)
    local chem_id = frame.args[1]
    
    if not (p.chem[chem_id] and p.chem[chem_id].color) then
        return "#000"
    end
    
    local basecol = p.chem[chem_id].color
    local red = tonumber(basecol:sub(2, 3), 16) or 0
    local grn = tonumber(basecol:sub(4, 5), 16) or 0
    local blu = tonumber(basecol:sub(6, 7), 16) or 0
    
    -- Вычисляем яркость
    local luminance = math.sqrt(0.241*red*red + 0.691*grn*grn + 0.068*blu*blu)
    
    if luminance > 100 then
        return mw.text.nowiki("#000")
    else
        return mw.text.nowiki("#FFF")
    end
end

-- Проверка наличия рецепта у химического вещества
function p.hasrecipe(frame)
    local chem_id = frame.args[1]
    
    if p.chem[chem_id] and p.chem[chem_id].recipes then
        return #p.chem[chem_id].recipes > 0
    end
    return false
end

-- Построение блоков для химических веществ
function p.buildboxes(frame)
    local group = frame.args[1]
    local out = ""
    
    for k, v in pairs(p.chem) do
        if group == nil or (v.group and v.group == group) then
            out = out .. frame:expandTemplate{ 
                title = "Chembox", 
                args = { prototype = k }
            }
        end
    end
    
    return out
end

-- Построение блоков реакций
function p.buildreactboxes(frame)
    local out = ""
    
    for k, v in pairs(p.react) do
        if v.effects and p.tablelength(v.effects) > 0 then
            out = out .. frame:expandTemplate{ 
                title = "Reactionbox", 
                args = { reaction = k }
            }
        end
    end
    
    return out
end

-- Построение рецептов для химического вещества
function p.buildrecipes(frame)
    local chem_id = frame.args[1]
    local out = ""
    
    if p.chem[chem_id] and p.chem[chem_id].recipes then
        for _, recipe_id in pairs(p.chem[chem_id].recipes) do
            out = out .. p.buildreaction(frame, recipe_id)
        end
    end
    
    return out
end

-- Построение конкретной реакции
function p.buildreactionext(frame)
    local react_id = frame.args[1]
    return p.buildreaction(frame, react_id)
end

-- Основная функция построения реакции
function p.buildreaction(frame, react_id)
    if not p.react[react_id] then
        return ""
    end
    
    local data = p.react[react_id]
    local args = {}
    
    -- Обрабатываем реагенты
    local i = 0
    if data.reactants then
        for reagent_id, reagent_data in pairs(data.reactants) do
            i = i + 1
            local dest = "Chemistry"
            
            if p.chem[reagent_id] and p.chem[reagent_id].group and p.groupDirection[p.chem[reagent_id].group] then
                dest = p.groupDirection[p.chem[reagent_id].group]
            end
            
            args["component-" .. i] = frame:expandTemplate{ 
                title = "Chem Recipe Component", 
                args = { 
                    reagent = reagent_id, 
                    amount = reagent_data.amount or reagent_data, 
                    dest = dest 
                }
            }
        end
    end
    
    -- Обрабатываем продукты
    i = 0
    if data.products then
        for product_id, amount in pairs(data.products) do
            i = i + 1
            local dest = "Chemistry"
            
            if p.chem[product_id] and p.chem[product_id].group and p.groupDirection[p.chem[product_id].group] then
                dest = p.groupDirection[p.chem[product_id].group]
            end
            
            args["result-" .. i] = frame:expandTemplate{ 
                title = "Chem Recipe Component", 
                args = { 
                    reagent = product_id, 
                    amount = amount, 
                    dest = dest 
                }
            }
        end
    end
    
    -- Обрабатываем эффекты
    if data.effects then
        args.effects = p.geneffectlist(data.effects, frame, 1)
    end
    
    return frame:expandTemplate{ title = "Chem Box Recipe", args = args }
end

-- Проверка на утоление жажды
function p.checksatiatesthirst(frame)
    local chem_id = frame.args[1]
    
    if not (p.chem[chem_id] and p.chem[chem_id].metabolisms) then
        return ""
    end
    
    for _, metabolism in pairs(p.chem[chem_id].metabolisms) do
        if metabolism.effects then
            for _, effect in pairs(metabolism.effects) do
                if effect.id == "SatiateThirst" then
                    return "1"
                end
            end
        end
    end
    
    return ""
end

-- Проверка на утоление голода
function p.checksatiateshunger(frame)
    local chem_id = frame.args[1]
    
    if not (p.chem[chem_id] and p.chem[chem_id].metabolisms) then
        return ""
    end
    
    for _, metabolism in pairs(p.chem[chem_id].metabolisms) do
        if metabolism.effects then
            for _, effect in pairs(metabolism.effects) do
                if effect.id == "SatiateHunger" then
                    return "1"
                end
            end
        end
    end
    
    return ""
end

-- Проверка наличия эффектов (кроме голода/жажды)
function p.haseffects(frame)
    local chem_id = frame.args[1]
    
    if not (p.chem[chem_id] and p.chem[chem_id].metabolisms) then
        return ""
    end
    
    for _, metabolism in pairs(p.chem[chem_id].metabolisms) do
        if metabolism.effects then
            for _, effect in pairs(metabolism.effects) do
                if effect.id ~= "SatiateHunger" and effect.id ~= "SatiateThirst" then
                    return "1"
                end
            end
        end
    end
    
    return ""
end

-- Генерация эффектов
function p.geneffects(frame, chem_id)
    if chem_id == nil then
        chem_id = frame.args[1]
    end
    
    if not (p.chem[chem_id] and p.chem[chem_id].metabolisms) then
        return ""
    end
    
    local out = ""
    for metabolism_type, metabolism_data in pairs(p.chem[chem_id].metabolisms) do
        local rate = metabolism_data.rate or 0.5
        out = out .. "<b>" .. metabolism_type .. "</b> (" .. rate .. " единиц в секунду)\n"
        
        if metabolism_data.effects then
            out = out .. p.geneffectlist(metabolism_data.effects, frame, rate)
        end
    end
    
    return out
end

-- Генерация списка эффектов
function p.geneffectlist(effects, frame, rate)
    local out = ""
    
    for _, effect in pairs(effects) do
        if effect.id == "HealthChange" then
            out = out .. ":" .. p.genhealthchange(effect, rate, frame) .. "\n"
        elseif effect.id == "AdjustReagent" then
            out = out .. ":" .. p.genadjustreagent(effect, rate, frame) .. "\n"
        elseif effect.id == "FlammableReaction" then
            out = out .. ":" .. p.genflammablereaction(effect, frame) .. "\n"
        elseif effect.id == "AdjustTemperature" then
            out = out .. ":" .. p.genadjusttemperature(effect, frame) .. "\n"
        elseif effect.id == "GenericStatusEffect" then
            out = out .. ":" .. p.gengenericstatuseffect(effect, frame) .. "\n"
        elseif effect.id == "ExplosionReactionEffect" then
            out = out .. ":" .. p.genexplosionreactioneffect(effect, frame) .. "\n"
        elseif effect.id == "FoamAreaReactionEffect" then
            out = out .. ":" .. p.genfoamareareactioneffect(effect, frame) .. "\n"
        elseif effect.id == "SmokeAreaReactionEffect" then
            out = out .. ":" .. p.gensmokeareareactioneffect(effect, frame) .. "\n"
        elseif effect.id == "ModifyBleedAmount" then
            out = out .. ":" .. p.genmodifybleedamount(effect, frame) .. "\n"
        end
    end
    
    return out
end

-- Генераторы для различных типов эффектов
function p.gensmokeareareactioneffect(effect, frame)
    local conds = ""
    if effect.conditions then 
        conds = p.genconds(effect.conditions, frame)
    end
    
    return frame:expandTemplate{ 
        title = "SmokeAreaReactionEffect", 
        args = { 
            when = conds, 
            prob = effect.probability 
        }
    }
end

function p.genfoamareareactioneffect(effect, frame)
    local conds = ""
    if effect.conditions then 
        conds = p.genconds(effect.conditions, frame)
    end
    
    return frame:expandTemplate{ 
        title = "FoamAreaReactionEffect", 
        args = { 
            when = conds, 
            prob = effect.probability 
        }
    }
end

function p.genexplosionreactioneffect(effect, frame)
    local conds = ""
    if effect.conditions then 
        conds = p.genconds(effect.conditions, frame)
    end
    
    return frame:expandTemplate{ 
        title = "ExplosionReactionEffect", 
        args = { 
            when = conds, 
            prob = effect.probability 
        }
    }
end

function p.gengenericstatuseffect(effect, frame)
    local conds = ""
    if effect.conditions then 
        conds = p.genconds(effect.conditions, frame)
    end
    
    return frame:expandTemplate{ 
        title = "GenericStatusEffect", 
        args = { 
            key = effect.Key, 
            type = effect.Type, 
            time = effect.Time, 
            refresh = effect.Refresh, 
            when = conds, 
            prob = effect.probability 
        }
    }
end

function p.genadjusttemperature(effect, frame)
    local conds = ""
    if effect.conditions then 
        conds = p.genconds(effect.conditions, frame)
    end
    
    return frame:expandTemplate{ 
        title = "AdjustTemperature", 
        args = { 
            amount = effect.Amount, 
            when = conds, 
            prob = effect.probability 
        }
    }
end

function p.genflammablereaction(effect, frame)
    local conds = ""
    if effect.conditions then 
        conds = p.genconds(effect.conditions, frame)
    end
    
    return frame:expandTemplate{ 
        title = "FlammableReaction", 
        args = { 
            multiplier = effect.Multiplier, 
            when = conds, 
            prob = effect.probability 
        }
    }
end

function p.genadjustreagent(effect, rate, frame)
    local conds = ""
    if effect.conditions then 
        conds = p.genconds(effect.conditions, frame)
    end
    
    return frame:expandTemplate{ 
        title = "AdjustReagent", 
        args = { 
            amount = effect.Amount, 
            reagent = effect.Reagent, 
            when = conds, 
            prob = effect.probability 
        }
    }
end

function p.genmodifybleedamount(effect, frame)
    local conds = ""
    if effect.conditions then 
        conds = p.genconds(effect.conditions, frame)
    end
    
    return frame:expandTemplate{ 
        title = "ModifyBleedAmount", 
        args = { 
            amount = effect.Amount, 
            when = conds, 
            prob = effect.probability 
        }
    }
end

function p.genhealthchange(effect, rate, frame)
    local healst = {}
    local dealst = {}
    local r = 1.0 / rate
    
    if effect.damage and effect.damage.types then
        for damage_type, amount in pairs(effect.damage.types) do
            if amount < 0 then
                healst[damage_type] = amount * r
            else
                dealst[damage_type] = amount * r
            end
        end
    end
    
    if effect.damage and effect.damage.groups then
        for damage_group, amount in pairs(effect.damage.groups) do
            if amount < 0 then
                healst[damage_group] = amount * r
            else
                dealst[damage_group] = amount * r
            end
        end
    end
    
    local heals = p.hchangelist(healst, frame)
    local deals = p.hchangelist(dealst, frame)
    local conds = ""
    
    if effect.conditions then 
        conds = p.genconds(effect.conditions, frame)
    end
    
    return frame:expandTemplate{ 
        title = "HealthChange", 
        args = { 
            heals = heals, 
            deals = deals, 
            when = conds, 
            prob = effect.probability 
        }
    }
end

function p.hchangelist(changes, frame)
    local out = ""
    local len = p.tablelength(changes)
    local i = 0
    
    for damage_type, amount in pairs(changes) do
        i = i + 1
        if len == i and i ~= 1 then
            out = out .. ", and "
        elseif i ~= 1 then
            out = out .. ", "
        end
        out = out .. p.hchange(damage_type, amount, frame)
    end
    
    return out
end

function p.hchange(damage_type, amount, frame)
    return frame:expandTemplate{ 
        title = "HealthModifier", 
        args = { 
            adj = amount, 
            kind = damage_type 
        }
    }
end

function p.genconds(conditions, frame)
    local out = ""
    local len = p.tablelength(conditions)
    local i = 0
    
    for _, condition in pairs(conditions) do
        i = i + 1
        if len == i and i ~= 1 then
            out = out .. ", and "
        elseif i ~= 1 then
            out = out .. ", "
        end
        out = out .. p.gencond(condition, frame)
    end
    
    return out
end

function p.gencond(condition, frame)
    if condition.id == "TotalDamage" then
        return frame:expandTemplate{ 
            title = "TotalDamage", 
            args = { 
                min = condition.Min, 
                max = condition.Max 
            }
        }
    elseif condition.id == "ReagentThreshold" then
        return frame:expandTemplate{ 
            title = "ReagentThreshold", 
            args = { 
                min = condition.Min, 
                max = condition.Max, 
                reagent = condition.Reagent 
            }
        }
    elseif condition.id == "OrganType" then
        return frame:expandTemplate{ 
            title = "OrganType", 
            args = { 
                shouldhave = condition.ShouldHave, 
                type = condition.Type 
            }
        }
    elseif condition.id == "Temperature" then
        return frame:expandTemplate{ 
            title = "Temperature", 
            args = { 
                min = condition.Min, 
                max = condition.Max 
            }
        }
    end
    
    return ""
end

-- Вспомогательные функции
function p.tablelength(table)
    local count = 0
    for _ in pairs(table) do 
        count = count + 1 
    end
    return count
end

function p.has_value(tab, val)
    for _, value in ipairs(tab) do
        if value[1] == val then
            return true
        end
    end
    return false
end

function p.strsplit(inputstr, separator)
    if separator == nil then
        separator = ","
    end
    
    local t = {}
    for str in string.gmatch(inputstr, "([^"..separator.."]+)") do
        table.insert(t, str)
    end
    
    return t
end

-- Функции для работы со статусами химических веществ
function p.getmetabolizertype(frame)
    local type_id = frame.args[1]
    
    if p.status[type_id] and p.status[type_id].type == "metabolizerType" then
        return p.status[type_id].name or type_id
    end
    
    return ""
end

function p.getmetabolismgroup(frame)
    local group_id = frame.args[1]
    
    if p.status[group_id] and p.status[group_id].type == "metabolismGroup" then
        return p.status[group_id].name or group_id
    end
    
    return ""
end

function p.getmixingcategory(frame)
    local category_id = frame.args[1]
    
    if p.status[category_id] and p.status[category_id].type == "mixingCategory" then
        return p.status[category_id].verbText or category_id
    end
    
    return ""
end

function p.getreactivegroup(frame)
    local group_id = frame.args[1]
    
    if p.status[group_id] and p.status[group_id].type == "reactiveGroup" then
        return group_id
    end
    
    return ""
end

return p