Toggle menu
15
236
70
27.5K
Kenshi Wiki
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.


From https://kenshi.fandom.com/wiki/Module:Vendor_List


local p = {}

-- TODO: Figure out a way to make this mw.loadData
local vendorData = require('Module:Vendor List/data')
local get_armour_grades = require('Module:Faction').get_armour_grades

local vendor_templates = {
    ['weapons'] = {title = 'Vendor/Weapon'},
    ['clothing'] = {title = 'Vendor/Armour'},
    ['items'] = {title = 'Vendor/Entry'}
}

function p.main(frame)
    local args = frame:getParent().args
    local names = string.split(args['vendors'],',')
    local closed = args['collapsed'] ~= nil
    local faction = args['faction']
    local rolls = args['rolls']

    return p._display_vendor(names, closed, faction, rolls, frame)
end

function p._display_vendor(vendors, closed, faction, rolls, frame)

    local data = p._convert_vendor_items(vendors, faction, rolls)

    if data == nil then
        return "Error: One of the vendors (" .. table.concat(vendors, " or ") .. ") was not found." -- TODO: Leave a module link so that the editor can be sure where and how to add the vendor
    end
    
    local result = ''

    result = result .. frame:expandTemplate({title = 'Vendor/Header', args = (closed and {collapsed = 'true'} or {})})

    for category, items in pairs(data) do
        local template = vendor_templates[category]

        if template ~= nil then
            result = result .. frame:expandTemplate({title = 'Vendor/Subheader', args = {firstToUpper(category), (category ~= 'items' and 'Manufacturer' or '')}})

            for i, chanceItem in ipairs(items) do
                template.args = {name = chanceItem[1], chance = string.format('%02.2f%%', chanceItem[2])}
                for j = 1, #chanceItem[3] do
                    local grade_name = chanceItem[3][j][1]
                    local grade_chance = chanceItem[3][j][2]
                    if grade_chance > 0 then
                        template.args[grade_name] = string.format('%02.2f', grade_chance)
                    end
                end

                if category == 'items' then
                    template.args.price = frame:expandTemplate({title = 'Price', args = {chanceItem[1]}})
                    template.args.item = template.args.name
                    template.args.name = nil
                end

                result = result .. frame:expandTemplate(template)
            end
        end
    end
    
    result = result .. frame:expandTemplate({title = 'Vendor/Footer'})
    return result
end

function p._convert_vendor_items(vendors, faction, rolls)
    local data = p._merge_vendors(vendors)

    if data == nil then
        return nil
    end

    local chance_sums = {}
    local results = {}
    local manufacturers = table.shallow_copy(data['weapon manufacturers'])
    local armour_grades = table.shallow_copy(get_armour_grades(faction))

    p._calculate_chance_sum(chance_sums, 'armour grades', armour_grades)

    for category, items in pairs(data) do
        if category ~= 'base' then
            if vendor_templates[category] then
                category = 'overall'
            end
            p._calculate_chance_sum(chance_sums, category, items)
        end
    end

    for i, _ in ipairs(manufacturers) do
        manufacturers[i] = {manufacturers[i][1], p._calculate_roll_probability(chance_sums['weapon manufacturers'], manufacturers[i][2], 1)}
    end

    for i, _ in ipairs(armour_grades) do
        armour_grades[i] = {armour_grades[i][1], p._calculate_roll_probability(chance_sums['armour grades'], armour_grades[i][2], 1)}
    end

    for category, items in pairs(data) do
        if category ~= 'base' then
            results[category] = {}
            
            local chances
            if vendor_templates[category] then
                chances = chance_sums['overall']
            else
                chances = chance_sums[category]
            end
            
            for _, chanceItem in ipairs(items) do
                local chance = p._calculate_roll_probability(chances, chanceItem[2], rolls)
                local grades

                if category == 'weapons' and manufacturers ~= nil then
                    grades = manufacturers
                elseif category == 'clothing' then
                    grades = armour_grades
                else
                    grades = {}
                end

                table.insert(results[category], {chanceItem[1], chance, grades})
            end
        end
    end

    for category, _ in pairs(results) do
        table.sort(results[category], compare)
    end
    
    return results
end

function p._calculate_chance_sum(chance_sums, category, items)
    local chance_sum = chance_sums[category] or 0

    for _, chanceItem in ipairs(items) do
        chance_sum = chance_sum + chanceItem[2]
    end
            
    chance_sums[category] = chance_sum
end

function p._calculate_roll_probability(chance_sum, chance, rolls)
    return (1 - ((chance_sum-chance) / chance_sum)^rolls) * 100
end

function p._merge_vendors(vendors)
    local results = {}

    for i, vendor in ipairs(vendors) do
        local data = vendorData[vendor]
        table.merge(results, data)
    end

    return results
end

function firstToUpper(str)
    return (str:gsub("^%l", string.upper))
end

function compare(a,b)
    return a[2] > b[2]
end

function table.shallow_copy(t)
    local t2 = {}
    for k,v in pairs(t) do
      t2[k] = v
    end
    return t2
end

function table.merge(t1, t2)
    for k,v in pairs(t2) do
        if type(v) == "table" then
            if type(t1[k] or false) == "table" then
                table.merge(t1[k] or {}, t2[k] or {})
            else
                t1[k] = v
            end
        else
            if type(t1[k] or false) == "number" then
                t1[k] = t1[k] + v
            end
        end
    end
    return t1
end

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

return p