Module:Moons/AutoTables

From Lethal Company Wiki

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

local p = {}

local WikiAutomated = require('Module:WikiAutomated')
local GameVersion = require('Module:GameVersion')
local Scraps = require('Module:Scraps')
local Entities = require('Module:Entities')
local Moons = require('Module:Moons')
local Rarities = require('Module:Rarities')
local I18n = require('Module:I18n')

--------------------
--#region lootTable
--------------------

function p._lootTableData(moon, version)
    local errors = {}

    local data = {
        version = GameVersion.parseVersion(version, Scraps.versions),
        extras = {},
        rows = {},
    }

    if Moons.isMoonExistInVersion(moon, version) then
        local totalRarity = Rarities.getItemsTotalRarity(moon, version)
        data.extras.totalRarity = totalRarity

        local rarities = Rarities.getItemsRarities(moon, version)
        for scrap_mName, rarity in pairs(rarities) do
            local row = {}

            local scrap = Scraps.getScrap(scrap_mName, version)
            row.scrap_mName = scrap_mName
            row.name = scrap.name
            row.rarity = rarity
            row.spawnChance = rarity / totalRarity * 100
            row.minValue = scrap.minValue
            row.maxValue = scrap.maxValue
            row.weight = scrap.weight
            row.conductive = scrap.conductive
            row.twoHanded = scrap.twoHanded

            table.insert(data.rows, row)
            table.sort(data.rows, function(a, b) return a.rarity > b.rarity end)
        end
    else
        table.insert(errors, 'moonNotAddedInVersion')
    end

    if #errors > 0 then
        data.errors = table.concat(errors, ',')
    end
    return data
end

function p._lootTableRender(tblDataRows, lang)
    local tableHeader = ([[
! rowspan=2 | %s
! rowspan=2 | %s
! colspan=3 | %s
! rowspan=2 | %s
! rowspan=2 | %s
! rowspan=2 | %s
|-
! %s !! %s !! %s
]]):format(
        I18n.getTranslation(lang, 'Scrap', 'ScrapTableHeaders'),
        I18n.getTranslation(lang, 'Spawn chance', 'ScrapTableHeaders'),
        I18n.getTranslation(lang, 'Values (c)', 'ScrapTableHeaders'),
        I18n.getTranslation(lang, 'Weight (lb)', 'ScrapTableHeaders'),
        I18n.getTranslation(lang, 'Is conductive', 'ScrapTableHeaders'),
        I18n.getTranslation(lang, 'Is two-handed', 'ScrapTableHeaders'),
        -- |-
        I18n.getTranslation(lang, 'Min', 'ScrapTableHeaders'),
        I18n.getTranslation(lang, 'Average', 'ScrapTableHeaders'),
        I18n.getTranslation(lang, 'Max', 'ScrapTableHeaders')
    )

    local tblContents = {}
    local tblContentTmpl = '| %s || %.2f%% || %s || %s || %s || %s || %s || %s'

    local contents = {
        '{| class="wikitable sortable"',
        tableHeader,
        '|-'
    }
    for _, rowData in ipairs(tblDataRows) do
        local minValue = Scraps.utils.scrapValue(rowData.minValue)
        local maxValue = Scraps.utils.scrapValue(rowData.maxValue)
        local weight = Scraps.utils.scrapWeight(rowData.weight)
        table.insert(tblContents, tblContentTmpl:format(
            I18n.getTranslationLink(lang, rowData.name, 'Scraps'),
            rowData.spawnChance,
            minValue,
            WikiAutomated.round((minValue + maxValue) / 2, 0),
            maxValue,
            weight,
            WikiAutomated.expandYesNoT(rowData.conductive),
            WikiAutomated.expandYesNoT(rowData.twoHanded)
        ))
    end

    local tbl_contents_concat = table.concat(tblContents, '\n|-\n')
    table.insert(contents, tbl_contents_concat)
    table.insert(contents, '|}')
    return table.concat(contents, '\n')
end

---return `moon`'s loot table
---@param moon string
---@param version version? see [[Module:GameVersion]] for default value
---@param lang string which language to use
function p._lootTable(moon, version, lang)
    local tblData = p._lootTableData(moon, version)
    return p._lootTableRender(tblData, lang)
end

function p.lootTable(frame)
    return p._lootTable(
        frame.args['moon'] or frame.args[1],
        frame.args['version'],
        frame.args['lang'] or mw.message.getDefaultLanguage().code
    )
end

function p._lootTableGrouped(moon)
    local moonVersions = Moons.versions

    local tblDatas = {}

    for _, version in ipairs(moonVersions) do
        local tblData = p._lootTableData(moon, version)
        if tblData.errors == nil then
            table.insert(tblDatas, tblData)
        else
            mw.log('version ' .. version .. ' skipped because errors: ' .. tblData.errors)
        end
    end

    return WikiAutomated.contentTables.group(tblDatas)
end

function p.lootTables(frame)
    return WikiAutomated.contentTables.groupRender(
        p._lootTableGrouped(frame.args['moon'] or frame.args[1]),
        p._lootTableRender,
        frame.args['lang'] or mw.message.getDefaultLanguage().code
    )
end

function p.lootTables_Auto()
    local frame = mw.getCurrentFrame()

    ---@type string
    local rootPagename = I18n.getLocalizedPageRootPageName(frame:preprocess('{{PAGENAME}}'))

    mw.log('LootTablesAuto: Generating tables on ' .. rootPagename)

    return WikiAutomated.contentTables.groupRender(
        p._lootTableGrouped(rootPagename),
        p._lootTableRender,
        mw.message.getDefaultLanguage().code
    )
end

--------------------
--#endregion lootTable
--------------------

--------------------
--#region entitiesSpawnChancesTable
--------------------

---@param entityType string one of the `Entities.getEntityType()` output
function p._entitiesSpawnChancesTableData(moon, entityType, version)
    local errors = {}

    local data = {
        version = GameVersion.parseVersion(version, Entities.versions),
        extras = {},
        rows = {},
    }

    if Moons.isMoonExistInVersion(moon, version) then
        data.extras.totalRarity = Rarities.getEntitiesTotalRarity(moon, entityType, version)

        local rarities = Rarities.getEntitiesRarities(moon, version)
        for entity_mName, rarity in pairs(rarities) do
            local row = {}

            local entity = Entities.getEntity(entity_mName, version)
            if entity.type == entityType and rarity ~= nil and rarity > 0 then
                row.entity_mName = entity_mName

                row.name = entity.name
                row.rarity = rarity
                row.spawnChance = rarity / data.extras.totalRarity * 100
                row.powerLevel = entity.powerLevel
                row.maxCount = entity.maxCount
                row.stunnable = entity.stunnable
                row.stunTimeMultiplier = entity.stunTimeMultiplier
                row.canDie = entity.canDie
                row.enemyHP = entity.enemyHP

                row.stunTimeSeconds = Entities.utils.stunTimeMultiplierToSeconds(
                    entity.stunTimeMultiplier, version
                )

                table.insert(data.rows, row)
            end
            table.sort(data.rows, function(a, b) return a.rarity > b.rarity end)
        end
    else
        table.insert(errors, 'moonNotAddedInVersion')
    end

    if #errors > 0 then
        data.errors = table.concat(errors, ',')
    end
    return data
end

function p._entitiesSpawnChancesTableRender(tblDataRows, lang)
    local frame = mw.getCurrentFrame()

    local tableHeadersTranslated = {
        I18n.getTranslation(lang, 'Entity', 'TableHeaders'),
        I18n.getTranslation(lang, 'Spawn chance', 'TableHeaders'),
        I18n.getTranslation(lang, 'Power level', 'TableHeaders'),
        I18n.getTranslation(lang, 'Max spawned', 'TableHeaders'),
        I18n.getTranslation(lang, 'Stunning', 'TableHeaders'),
        I18n.getTranslation(lang, 'HP', 'TableHeaders'),
    }

    local contents = {
        '{| class="wikitable sortable"',
        '! ' .. table.concat(tableHeadersTranslated, ' !! '),
        '|-'
    }
    local tblContents = {}
    -- | name || spawn chance || power level || max count || stun multiplier || HP
    local tblContentTmpl = '| %s || %.2f%% || %s || %s || %s || %s'

    ---[[formatting stun multiplier to a more human readable expression]]
    ---@param stunTimes { stunGrenade: number, homemadeFlashbang: number?, radarBooster: number? }|nil
    ---@param stunMultiplier number
    local function stunTimeMultiplierToReadable(stunTimes, stunMultiplier)
        if stunTimes == nil then
            return frame:expandTemplate { title = 'No_T', args = { 'Not stunnable' } }
        end

        local stunTimeContentTmpl = '<span style="white-space: nowrap; margin-inline-end: 0.5em;"><span>%s</span> <span>%.1fs</span></span>'
        local stunTimeReadableContents = {}

        local grenade = stunTimes.stunGrenade
        local flashbang = stunTimes.homemadeFlashbang
        local radar = stunTimes.radarBooster

        local grenadeIcon = ('[[File:Stun Grenade Icon.png|link=%s|20px]]'):format(
            I18n.getLocalizedPageLink('Stun Grenade', lang)
        )
        local flashbangIcon = ('[[File:DIYFlashbangRender.png|link=%s|20px]]'):format(
            I18n.getLocalizedPageLink('Homemade Flashbang', lang)
        )
        local radarIcon = ('[[File:Radar Booster Icon.png|link=%s|20px]]'):format(
            I18n.getLocalizedPageLink('Radar Booster', lang)
        )

        if grenade ~= nil and grenade == flashbang then
            local _content = stunTimeContentTmpl:format(grenadeIcon .. flashbangIcon, grenade)
            table.insert(stunTimeReadableContents, _content)
        else
            if grenade ~= nil then
                local _content = stunTimeContentTmpl:format(grenadeIcon, grenade)
                table.insert(stunTimeReadableContents, _content)
            end

            if flashbang ~= nil then
                local _content = stunTimeContentTmpl:format(flashbangIcon, flashbang)
                table.insert(stunTimeReadableContents, _content)
            end
        end

        if radar ~= nil then
            local _content = stunTimeContentTmpl:format(radarIcon, radar)
            table.insert(stunTimeReadableContents, _content)
        end

        local mainContents = ''
        for i, content in ipairs(stunTimeReadableContents) do
            mainContents = mainContents .. content
            if i % 2 == 0 and i ~= #stunTimeReadableContents then
                mainContents = mainContents .. '<br/>'
            end
        end

        mainContents = mainContents .. ('<br/><small>%s: %s</small>'):format(
            I18n.getTranslation(lang, 'Stun multiplier'), stunMultiplier
        )

        return '<div>' .. mainContents .. '</div>'
    end

    for _, row in ipairs(tblDataRows) do
        local stunRowContent
        if row.stunnable then
            stunRowContent = stunTimeMultiplierToReadable(row.stunTimeSeconds, row.stunTimeMultiplier)
        else
            stunRowContent = stunTimeMultiplierToReadable(nil)
        end

        local enemyHPRowContent
        if row.canDie and row.enemyHP ~= "-1" then
            enemyHPRowContent = ('[[File:Shovel Icon.png|link=%s|20px]] %s'):format(
                I18n.getLocalizedPageLink('Shovel', lang), row.enemyHP
            )
        else
            enemyHPRowContent = frame:expandTemplate { title = 'No_T', args = { 'Not killable' } }
        end

        table.insert(tblContents, tblContentTmpl:format(
            I18n.getLocalizedPageLink(row.name, lang),
            row.spawnChance,
            row.powerLevel,
            row.maxCount,
            stunRowContent,
            enemyHPRowContent
        ))
    end

    local tbl_contents_concat = table.concat(tblContents, '\n|-\n')
    table.insert(contents, tbl_contents_concat)
    table.insert(contents, '|}')
    return table.concat(contents, '\n')
end

---@param moon string
---@param version version? see [[Module:GameVersion]] for default value
---@param lang string which language to use
function p._entitiesSpawnChancesTable(moon, entityType, version, lang)
    local tblData = p._entitiesSpawnChancesTableData(moon, entityType, version)
    return p._entitiesSpawnChancesTableRender(tblData.rows, lang)
end

function p.entitiesSpawnChancesTable(frame)
    return p._entitiesSpawnChancesTable(
        frame.args['moon'] or frame.args[1],
        frame.args['entityType'] or frame.args[2],
        frame.args['version'],
        frame.args['lang'] or mw.message.getDefaultLanguage().code
    )
end

function p._entitiesSpawnChancesTableGrouped(moon, entityType)
    local versions = Entities.versions

    local tblDatas = {}

    for _, version in ipairs(versions) do
        local tblData = p._entitiesSpawnChancesTableData(moon, entityType, version)
        if tblData.errors == nil then
            table.insert(tblDatas, tblData)
        else
            mw.log('version ' .. version .. ' skipped because errors: ' .. tblData.errors)
        end
    end

    return WikiAutomated.contentTables.group(tblDatas)
end

function p.entitiesSpawnChancesTables(frame)
    return WikiAutomated.contentTables.groupRender(
        p._entitiesSpawnChancesTableGrouped(
            frame.args['moon'] or frame.args[1],
            frame.args['entityType'] or frame.args[2]
        ),
        p._entitiesSpawnChancesTableRender,
        frame.args['lang'] or mw.message.getDefaultLanguage().code
    )
end

--[[wrapper for the auto tables below]]
function p._entitiesSpawnChancesTables_AutoWrapper(entityType)
    local frame = mw.getCurrentFrame()

    ---@type string
    local rootPagename = I18n.getLocalizedPageRootPageName(
        frame:preprocess('{{PAGENAME}}')
    )

    mw.log('EntitiesSpawnChancesTablesAuto: Generating tables on ' .. rootPagename)

    return WikiAutomated.contentTables.groupRender(
        p._entitiesSpawnChancesTableGrouped(rootPagename, entityType),
        p._entitiesSpawnChancesTableRender,
        mw.message.getDefaultLanguage().code
    )
end

function p.entitiesSpawnChancesTables_AutoIndoor()
    return p._entitiesSpawnChancesTables_AutoWrapper('indoor')
end

function p.entitiesSpawnChancesTables_AutoNighttime()
    return p._entitiesSpawnChancesTables_AutoWrapper('nighttime')
end

function p.entitiesSpawnChancesTables_AutoDaytime()
    return p._entitiesSpawnChancesTables_AutoWrapper('daytime')
end

--------------------
--#endregion entitiesSpawnChancesTable
--------------------

return p