Module:Research

From Space Station 14 Wiki
Revision as of 17:51, 7 September 2024 by Aliser (talk | contribs) (wip)

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

local p = {} --p stands for package
local getArgs = require('Module:Arguments').getArgs
local itemModule = require('Module:Item')
local yesNo = require('Module:Yesno')

local techs_by_tech_ids_by_discipline_ids = mw.loadJsonData("Module:Research/techs by tech IDs by discipline IDs.json")

local disciplines_by_discipline_ids = mw.loadJsonData("Module:Research/disciplines by discipline IDs.json")

local current_frame = mw:getCurrentFrame()

local was_template_styles_tag_el_added = false

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


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

local function table_has_value(tab, val)
	for _, value in ipairs(tab) do
		if value == val then
			return true
		end
	end

	return false
end

local function assert_value_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

-- Given a value, checks if it's "nil".
-- * If it's not - returns the `value`.
-- * IF it is - returns the `value_if_nil`.
local function nil_or(value, value_if_nil)
	if value == nil then
		return value_if_nil
	else
		return value
	end
end

local function find_first_numeric_table_item_matching_condition(table, condition)
	for i, item in ipairs(table) do
		if condition(item, i, table) then
			return item
		end
	end
end

local function find_first_table_item_matching_condition(table, condition)
	for key, value in pairs(table) do
		if condition(key, value, table) then
			return value
		end
	end
end

local function find_first_table_item_key_matching_condition(table, condition)
	for key, value in pairs(table) do
		if condition(key, value, table) then
			return key
		end
	end
end

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

-- Checks whether there's a research by name or ID.
-- Name can be in any casing, but if using ID - the casing must match exactly.
function p.research_exists_by_name_or_id(research_name_or_id)
	return p.try_lookup_research(research_name_or_id) ~= nil
end


-- Lookups research by name or ID.
-- Name can be in any casing, but if using ID - the casing must match exactly.
-- 
-- Returns a table containg `discipline_id`, `research_id` and `research`.
-- If no reserach was found, returns `nil`.
function p.try_lookup_research(research_name_or_id)
	local lowercase_research_name_or_id = string.lower(research_name_or_id)

	for discipline_id, researches_by_id in pairs(techs_by_tech_ids_by_discipline_ids) do
		for research_id, research in pairs(researches_by_id) do
			assert_value_not_nil(research.name, "failed to lookup a research: research by ID '" .. research_id .."' doesn't have a 'name' defined")

			if(research_id == research_name_or_id or string.lower(research.name) == lowercase_research_name_or_id) then
				return {
					discipline_id = discipline_id,
					research_id = research_id,
					research = research
				}
			end
		end
	end
end

-- Lookups research by name or ID.
-- Name can be in any casing, but if using ID - the casing must match exactly.
-- 
-- Returns a table containg `discipline_id`, `research_id` and `research`.
-- If no reserach was found, raises an error.
function p.lookup_research(research_name_or_id)
	local result = p.try_lookup_research(research_name_or_id)
	if result == nil then
		error("failed to lookup a research: research with name/ID '" .. research_name_or_id .. "' was not found");
	else
		return result
	end
end




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

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

	local research_query = args[1]
	assert_value_not_nil(research_query, "failed to generate a research card: research name was not provided")

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

	local research_lookup_result = p.try_lookup_research(research_query)
	if research_lookup_result == nil then
		error("failed to generate a research card: no research was found found by name/ID: " + research_query)
	end

	-- todo move asserts out?
	assert_value_not_nil(research_lookup_result.research.name)
	assert_value_not_nil(research_lookup_result.research.tier)
	assert_value_not_nil(research_lookup_result.research.cost)
	assert_value_not_nil(research_lookup_result.research.recipeUnlocks)

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


	local research_card_el = mw.html.create("div")
		:addClass("research-card")


	if not was_template_styles_tag_el_added then
		research_card_el:node(current_frame:extensionTag("templatestyles", "", { src = 'Template:Research/styles.css' }))

		was_template_styles_tag_el_added = true
	end


	-- todo 
	local icon_el = itemModule.generate_item{ "PlushieLizard", label = "", size = "84px", link = '' }
		:addClass("research-card-icon")

	research_card_el:node(icon_el)


	local header_el = mw.html.create("div")
		:addClass("research-card-header")

	research_card_el:node(header_el)


	local header_text_el = mw.html.create("span")
		:addClass("research-card-header-text")
		:node(research_lookup_result.research.name)

	header_el:node(header_text_el)


	-- discipline icon el
	-- todo replace with icon
	header_text_el:node(
		itemModule.generate_item{ "PlushieLizard", label = "", size = "24px", link = '' }
			:addClass("research-card-header-discipline-icon")
	)


	-- todo color
	-- todo replace discipline ID with name 
	local tier_and_discipline_text_el = mw.html.create("span")
		:addClass("research-card-header-tier-and-discipline")
		:node("Tier " .. research_lookup_result.research.tier .. ", ")
		:node(
			mw.html.create("span")
				:css("color", "white")
				:node(research_lookup_result.discipline_id)
		)

	header_el:node(tier_and_discipline_text_el)


	local body_el = mw.html.create("div")
		:addClass("research-card-body")

	research_card_el:node(body_el)


	-- todo cost color
	local cost_el = mw.html.create("span")
		:addClass("research-card-body-cost")
		:node("Cost: " .. research_lookup_result.research.cost)

	body_el:node(cost_el)


	-- unlocks label el
	body_el:node("Unlocks:")


	local unlocks_el = mw.html.create("ul")
		:addClass("research-card-body-unlocks")

	-- todo recipe names
	-- todo expanding recipe names to recipes. maybe a tooltip?
	for _, recipe_id in ipairs(research_lookup_result.research.recipeUnlocks) do
		unlocks_el:node(
			mw.html.create("li")
				:addClass("research-card-body-unlocks-unlock")
				:node(recipe_id)
		)
	end

	body_el:node(unlocks_el)


	return research_card_el
		:allDone()
end

return p