Module:ResearchCost

From Oxygen Not Included Wiki
Jump to navigation Jump to search
This module uses the Cargo extension.
This module uses Extension:Cargo, an integral part of the wiki's back-end.
  • This module queries the table "Research". View table.

This module allows for easy and quick lookup of one or all type(s) of Research costs. It looks up the costs based on the provided research tier number, and returns them in one of several formats.

The main function that it exposes is getCode. It is invoked by Template:ResearchCost, which also describes its usage in greater detail. Alternatively, the comments in the module code describe its functionality.

It is generally recommended to use Template:ResearchCost instead of invoking this module directly.





local p = {}
local mergeArgs = require("Module:ProcessArgs").merge

-- List of costs by tier then by type, as the game defines them
local TECH_TIERS_BASE = {
    {},
    { basic=15 },
    { basic=20 },
    { basic=30, advanced=20 },
    { basic=35, advanced=30 },
    { basic=40, advanced=50 },
    { basic=50, advanced=70 },
    { basic=70, advanced=100 },
    { basic=70, advanced=100, space=200 },
    { basic=70, advanced=100, space=400 },
    { basic=70, advanced=100, space=800 },
    { basic=70, advanced=100, space=1600 },
    keys={'basic', 'advanced', 'space'}
}
local TECH_TIERS_SO = {
    {},
    { basic=15 },
    { basic=20 },
    { basic=30,  advanced=20 },
    { basic=35,  advanced=30 },
    { basic=40,  advanced=50,  orbital=0,   nuclear=20 },
    { basic=50,  advanced=70,  orbital=30,  nuclear=40 },
    { basic=70,  advanced=100, orbital=250, nuclear=370 },
    { basic=100, advanced=130, orbital=400, nuclear=435 },
    { basic=100, advanced=130, orbital=600 },
    { basic=100, advanced=130, orbital=800 },
    { basic=100, advanced=130, orbital=1600 },
    keys={'basic', 'advanced', 'nuclear', 'orbital'}
}
-- Mapping of research type keys to display names
local ResearchTypes = {
    basic = {
    	key='basic',
    	name='Novice Research',
    	shorthand='Novice',
    	barClass='research-novice',
    	image='File:Novice-Research.png'
    },
    advanced = { 
    	key='advanced',
    	name='Advanced Research',
    	shorthand='Advanced',
    	barClass='research-intermediate',
    	image='File:Advanced Research.png'
    },
    space = { 
    	key='space',
    	name='Interstellar Research',
    	shorthand='Interstellar',
    	barClass='research-interstellar',
    	image='File:Interstellar Research.png'
    },
    nuclear = { 
    	key='nuclear',
    	name='Applied Sciences Research',
    	shorthand='Applied Sciences',
    	barClass='research-matscience',
    	image='File:Materials Science Research.png'
    },
    orbital = { 
    	key='orbital',
    	name='Data Analysis Research',
    	shorthand='Data Analysis',
    	barClass='research-interstellar',
    	image='File:Orbital Research.png'
    },
}

-- Helper function for determining if a given flag is set
-- in a function's arguments
local isFlagSet = function(flag)
    if flag then
        local word = tostring(flag)
	    return #word > 0 and tostring(flag) ~= 'false' and tostring(flag):sub(1, 1):lower() ~= 'n'
    else
        return false
    end
end

local getTypeKey = function(arg)
    for k,v in pairs(ResearchTypes) do
        if string.lower(k) == string.lower(arg) or string.lower(v.shorthand) == string.lower(arg) then
            return v.key
        end
    end
    return nil
end

local getOneCost = function(frame, args, tier, type, format)
	local size = nil
	if args and args.size then
		size = tonumber(args.size)
		if not size or size <= 8 then size = nil end
	end
	size = size or 18
    if not tier or not tier[type] or not ResearchTypes[type] then
        return '0'
    end
    if format == 'value' then
        return tier[type]
    elseif format == 'map' then
        return ResearchTypes[type].name .. '=' .. tier[type]
    elseif format == 'bar' then
    	if tier[type] <= 0 then return '' end
    	local curName = ResearchTypes[type].name
    	return string.format('|-\n| class="research-bar %s" | %d || [[%s|%dx%dpx|%s|link=%s]]',
    		ResearchTypes[type].barClass,
    		tier[type],
			ResearchTypes[type].image,
			size,
			size,
			curName,
			curName)
    end
    return ResearchTypes[type].name .. ': ' .. tier[type]
end

local getTotalCost = function(frame, args, isSO)
	local firstArg = (args[2] and #args[2] > 0 and 2) or 1
	local myType = getTypeKey(args[firstArg])
	if not myType then return '' end
	
	local fieldOne = (isSO and 'IF(tierSO IS NULL, tier, tierSO)=myTier') or 'tier=myTier'
	local whereOne = (isSO and "contentSO='1'") or "contentBase='1'"
	local queryResult = mw.ext.cargo.query('Research',
		fieldOne..",count(*)=count",
		{
			where = whereOne,
			groupBy = "myTier",
			orderBy = "myTier asc"
		}
	)
	if #queryResult < 1 then return 0 end
	
	local total = 0
	local myTiers = {TECH_TIERS_BASE, TECH_TIERS_SO}
	myTiers = myTiers[(isSO and 2) or 1]
	for i,v in ipairs(queryResult) do
		local t = tonumber(v.myTier)+1
		if myTiers[t] and myTiers[t][myType] then
			total = total + v.count * myTiers[t][myType]
		end
	end
	return total
end

-- Arguments:
-- [1] - the research tier #
-- [2] - (optional) the research type to look up, by shorthand (e.g. "applied
--         sciences") or by key (e.g. "nuclear"), case-insensitive
-- ['SO' or 'so'] - set to falsy (0, false, 'no', 'N') for base game, else Spaced Out!
-- ['format'] - format to return the results in (inly if args[2] is not specified).
--
-- See the documentation for Template:ResearchCost for more details.
function p.getCost(frame)
    local args = frame
	if frame == mw.getCurrentFrame() then
		args = mergeArgs(true)
	else
		frame = mw.getCurrentFrame()
	end
	
	local isSO = isFlagSet(args.so or args.SO or false)
    local dlc = (isSO and 2) or 1
	
	local format = string.lower(args.format or 'default')
	local result = ''
    local delim = '\n'
    local subfmt = format
    local skipMissing = true
    if format == 'list' then
        delim = ','
        subfmt = 'value'
        skipMissing = false
        dlc = 'both'
    elseif format == 'map' then
        delim = ','
    elseif format == 'total' then
    	return getTotalCost(frame, args, isSO)
    elseif format == 'value' then
        return ''
    end

	local allTiers = {TECH_TIERS_BASE, TECH_TIERS_SO}
	for i,tiers in ipairs(allTiers) do
		if dlc == 'both' or dlc == i then
		    local tierNum = (args[1] and tonumber(args[1])) or -1
		    if not tierNum or tierNum < 0 or tierNum >= #tiers then
		        return ''
		    end
		    local myTier = tiers[tierNum+1]
		
		    if args[2] then
		        local myType = getTypeKey(args[2])
		        if not myType then return '' end
		        return getOneCost(frame, args, myTier, myType, 'value')
		    end
		
			local typeKeys = tiers.keys
		    for _,type in ipairs(typeKeys) do
		        if (myTier[type] and myTier[type] > 0) or not skipMissing then
		            if #result > 0 then
		                result = result .. delim
		            end
		            result = result .. getOneCost(frame, args, myTier, type, subfmt)
		        end
		    end
	    end
	end
    return result
end

return p