Module:Weight table: Difference between revisions

From Space Station 14 Wiki
Aliser (talk | contribs)
Created page with "local p = {} local getArgs = require('Module:Arguments').getArgs local yesNo = require('Module:Yesno') -- ========================== local table_paths = { ["xeno triggers"] = "Module:Weigh table/data/xeno triggers.json" } -- ========================== local tables = {} -- ========================== local function assert_not_nil(value, error_message) if value == nil then if error_message == nil then error("value is nil") else..."
 
Aliser (talk | contribs)
add xeno effects
 
(5 intermediate revisions by the same user not shown)
Line 6: Line 6:


local table_paths = {
local table_paths = {
     ["xeno triggers"] = "Module:Weigh table/data/xeno triggers.json"
     ["xeno triggers"] = "Module:Weight table/data/xeno triggers.json",
    ["xeno effects"] = "Module:Weight table/data/xeno effects.json",
}
}


Line 110: Line 111:
end
end


-- Sorts a table into a new table.
-- An alternative to cases such as when table.sort is not working,
-- like when trying to sort JSON tables (thanks fuckass lua).
function table_to_sorted(tbl, sortfn)
    local keys = {}


-- ==========================
    for key, _ in pairs(tbl) do
        table.insert(keys, key)
    end
 
    table.sort(keys, function(keyA, keyB) return sortfn(tbl[keyA], tbl[keyB]) end)
 
    local t2 = {}
 
    for _, key in ipairs(keys) do
        table.insert(t2, tbl[key])
    end


local function generate_mode_error_message(mode, msg)
     return t2
     return "mode '" .. mode .. "' selected, but " .. msg
end
end
-- ==========================


local function find_weight_entry_by_weight_id_or_name(table, query)
local function find_weight_entry_by_weight_id_or_name(table, query)
Line 133: Line 150:
end
end


local arg_seq_reader = {
local function sort_by_weight_comparator(a, b)
    initialized = false,
     assert_not_nil(a.weight, "failed to sort a weight table: encountered an entry without a 'weight' property")
    args = nil,
     assert_not_nil(b.weight, "failed to sort a weight table: encountered an entry without a 'weight' property")
    index = 1
}
 
function arg_seq_reader.init(args, start_index)
     arg_seq_reader.initialized = true
    arg_seq_reader.args = args;
    arg_seq_reader.index = start_index;
end
 
function arg_seq_reader.is_done()
    if not arg_seq_reader.initialized then
        error("failed to check if iteration is done for arg reader: not initialized")
     end
 
    return arg_seq_reader.args[arg_seq_reader.index + 1] == nil
end
 
function arg_seq_reader.next()
    if not arg_seq_reader.initialized then
        error("failed to advance arg reader: not initialized")
    elseif arg_seq_reader.is_done() then
        error("failed to advance arg reader: iteration is done")
    end


    arg_seq_reader.index = arg_seq_reader.index + 1
     return a.weight > b.weight;
     return arg_seq_reader.args[arg_seq_reader.index]
end
end


Line 171: Line 164:
     local table_name = args[1]
     local table_name = args[1]
     assert_not_nil(table_name, "table not provided")
     assert_not_nil(table_name, "table not provided")
    local percentage_round = args.percentage_round or 3


     -- ============
     -- ============
Line 182: Line 177:
         tbl = mw.loadJsonData(table_path)
         tbl = mw.loadJsonData(table_path)
         tables[table_name] = tbl
         tables[table_name] = tbl
        tbl = table_to_sorted(tbl, sort_by_weight_comparator)
     end
     end


Line 187: Line 184:
         local weight = value.weight;
         local weight = value.weight;
         assert_not_nil("failed to calculate a total weight for a table '" ..
         assert_not_nil("failed to calculate a total weight for a table '" ..
        table_name .. "': encountered an entry without a 'weight' property (index " .. i .. ")")
            table_name .. "': encountered an entry without a 'weight' property (index " .. i .. ")")


         return accum + weight
         return accum + weight
Line 194: Line 191:


     local tbl_el = mw.html.create("table")
     local tbl_el = mw.html.create("table")
        :addClass("wikitable")
         :addClass("weight-table")
         :addClass("weight-table")


     local th = tbl_el:tag("th")
     -- local th = tbl_el:tag("th")
     th:tag("td"):wikitext("Name")
     local header = tbl_el:tag("tr")
     th:tag("td"):wikitext("ID")
    header:tag("th"):wikitext("Name")
     th:tag("td"):wikitext("Weight")
     header:tag("th"):wikitext("ID")
     th:tag("td"):wikitext("Percentage")
     header:tag("th"):wikitext("Weight")
     header:tag("th"):wikitext("Chance")


     for i, entry in ipairs(tbl) do
     for i, entry in ipairs(tbl) do
Line 215: Line 214:
             "failed to generate a weight table: encountered an entry without an 'weight' property (index " .. i .. ")")
             "failed to generate a weight table: encountered an entry without an 'weight' property (index " .. i .. ")")


         local fraction = weight / total_weight
         local percentage = weight / total_weight * 100
         local fraction_display = tostring(fraction * 100) .. "%"
         local percentage_rounded_str = string.format("%." .. percentage_round .. "f", percentage)
        local was_percentage_rounded = tostring(percentage) ~= percentage_rounded_str
 
        local percentage_display = (was_percentage_rounded and "≈" or "") .. percentage_rounded_str .. "%"


         local tr = tbl_el:tag("tr")
         local tr = tbl_el:tag("tr")


         tr:tag("td"):wikitext(name)
         tr:tag("td"):wikitext(name)
         tr:tag("td"):wikitext(id)
         tr:tag("td"):wikitext("<code>" .. id .. "</code>")
         tr:tag("td"):wikitext(weight)
         tr:tag("td"):wikitext(weight)
         tr:tag("td"):wikitext(fraction_display)
         tr:tag("td"):wikitext(percentage_display)
     end
     end



Latest revision as of 13:34, 14 May 2025

Module documentation
View or edit this documentation (about module documentation)

Implements {{Weight table}}.


local p = {}
local getArgs = require('Module:Arguments').getArgs
local yesNo = require('Module:Yesno')

-- ==========================

local table_paths = {
    ["xeno triggers"] = "Module:Weight table/data/xeno triggers.json",
    ["xeno effects"] = "Module:Weight table/data/xeno effects.json",
}

-- ==========================

local tables = {}

-- ==========================

local function assert_not_nil(value, error_message)
    if value == nil then
        if error_message == nil then
            error("value is nil")
        else
            error(error_message)
        end
    end
end

local function starts_with(str, substr)
    return string.sub(str, 1, string.len(substr)) == substr
end

local function ends_with(str, substr)
    local substr_length = string.len(substr)
    return string.sub(str, string.len(str) - substr_length + 1, string.len(str)) == substr
end

local function starts_with_insensitive(str, substr)
    return starts_with(string.lower(str), string.lower(substr))
end

local function ends_with_insensitive(str, substr)
    return ends_with(string.lower(str), string.lower(substr))
end

local function table_filter(tbl, filterFn)
    local out = {}

    for k, v in pairs(tbl) do
        if filterFn(v, k, tbl) then out[k] = v end
    end

    return out
end

local function num_table_reduce(tbl, reduceFn, initial_value)
    local out = initial_value

    for i, v in ipairs(tbl) do
        out = reduceFn(out, v, i, tbl)
    end

    return out
end

local function table_find(tbl, findFn)
    for k, v in pairs(tbl) do
        if findFn(v, k, tbl) then return v end
    end
end

local function table_contains(tbl, findFn)
    return table_find(tbl, findFn) ~= nil
end

local function table_contains_value(tbl, value)
    return table_find(tbl, function(iter_value)
        return iter_value == value
    end) ~= nil
end

local function table_find_key(tbl, findFn)
    for k, v in pairs(tbl) do
        if findFn(v, k, tbl) then return k end
    end
end

local function table_find_index(tbl, findFn)
    for i, v in ipairs(tbl) do
        if findFn(v, i, tbl) then return i end
    end
end

local function table_map(tbl, mapFn)
    local res = {}
    for k, v in pairs(tbl) do
        table.insert(res, mapFn(v, k, tbl))
    end
    return res
end

local function numeric_table_length(t)
    local count = 0
    for _ in ipairs(t) do count = count + 1 end
    return count
end

local function table_length(t)
    local count = 0
    for _ in pairs(t) do count = count + 1 end
    return count
end

-- Sorts a table into a new table.
-- An alternative to cases such as when table.sort is not working,
-- like when trying to sort JSON tables (thanks fuckass lua).
function table_to_sorted(tbl, sortfn)
    local keys = {}

    for key, _ in pairs(tbl) do
        table.insert(keys, key)
    end

    table.sort(keys, function(keyA, keyB) return sortfn(tbl[keyA], tbl[keyB]) end)

    local t2 = {}

    for _, key in ipairs(keys) do
        table.insert(t2, tbl[key])
    end

    return t2
end

-- ==========================

local function find_weight_entry_by_weight_id_or_name(table, query)
    local query_lc = string.lower(query)

    for _, entry in ipairs(table) do
        local id = entry.id
        if string.lower(id) == query_lc then
            return entry
        end

        local display = entry.display
        if string.lower(display) == query_lc then
            return entry
        end
    end
end

local function sort_by_weight_comparator(a, b)
    assert_not_nil(a.weight, "failed to sort a weight table: encountered an entry without a 'weight' property")
    assert_not_nil(b.weight, "failed to sort a weight table: encountered an entry without a 'weight' property")

    return a.weight > b.weight;
end

-- ==========================

function p.main(frame)
    local args = getArgs(frame)

    local table_name = args[1]
    assert_not_nil(table_name, "table not provided")

    local percentage_round = args.percentage_round or 3

    -- ============

    local tbl = tables[table_name]

    if tbl == nil then
        local table_path = table_paths[table_name]
        assert_not_nil(table_path, "unknown table '" .. table_name .. "'")

        tbl = mw.loadJsonData(table_path)
        tables[table_name] = tbl

        tbl = table_to_sorted(tbl, sort_by_weight_comparator)
    end

    local total_weight = num_table_reduce(tbl, function(accum, value, i)
        local weight = value.weight;
        assert_not_nil("failed to calculate a total weight for a table '" ..
            table_name .. "': encountered an entry without a 'weight' property (index " .. i .. ")")

        return accum + weight
    end, 0)


    local tbl_el = mw.html.create("table")
        :addClass("wikitable")
        :addClass("weight-table")

    -- local th = tbl_el:tag("th")
    local header = tbl_el:tag("tr")
    header:tag("th"):wikitext("Name")
    header:tag("th"):wikitext("ID")
    header:tag("th"):wikitext("Weight")
    header:tag("th"):wikitext("Chance")

    for i, entry in ipairs(tbl) do
        local id = entry.id
        assert_not_nil(id,
            "failed to generate a weight table: encountered an entry without an 'id' property (index " .. i .. ")")

        local name = entry.display
        assert_not_nil(name,
            "failed to generate a weight table: encountered an entry without an 'name' property (index " .. i .. ")")

        local weight = entry.weight
        assert_not_nil(weight,
            "failed to generate a weight table: encountered an entry without an 'weight' property (index " .. i .. ")")

        local percentage = weight / total_weight * 100
        local percentage_rounded_str = string.format("%." .. percentage_round .. "f", percentage)
        local was_percentage_rounded = tostring(percentage) ~= percentage_rounded_str

        local percentage_display = (was_percentage_rounded and "≈" or "") .. percentage_rounded_str .. "%"

        local tr = tbl_el:tag("tr")

        tr:tag("td"):wikitext(name)
        tr:tag("td"):wikitext("<code>" .. id .. "</code>")
        tr:tag("td"):wikitext(weight)
        tr:tag("td"):wikitext(percentage_display)
    end

    return tbl_el
end

return p