Module:EnemyStats2/Table

From Darkest Dungeon Wiki
Jump to navigation Jump to search
Template-info.svg Documentation

Implements the functionality in Template:EnemyStats2/Table.


local Cargo = mw.ext.cargo

local Histogram = require("Module:Histogram")
local Regions = require("Module:Regions2")
local TableArguments = require("Module:TableArguments")
local Types = require("Module:EnemyStats2/Types")
local Utils = require("Module:EnemyStats2/Utils")

local function query(search_parameter, search_value, hs)
	local tables = {
		"EnemyStats2=S",
		"EnemyStats2Types=T",
	}

	local fields = {
		"S.name=name",
		"icon",
		"article",
		"is_boss",
		"champion_of",
		"minion_of",
		-- Cargo doesn't support CASE statements?
		[[IF(is_boss=1, 3,
		IF(champion_of IS NOT NULL, 1,
		IF(minion_of IS NOT NULL, 2,
		0
		)))=tier_key]],
		"region",
		"GROUP_CONCAT(T.type ORDER BY T.type SEPARATOR ' ')=types"
	}
	for _, stat in ipairs(Utils.STATS) do
		table.insert(fields, stat.name)
	end

	local join_keys = {
		"S.name=T.name"
	}
	local order_keys = {
		"tier_key",
		"hp",
		"name",
	}

	local where = nil
	if search_parameter == "name" then
		where = ("S.name='%s'"):format(search_value)
	elseif search_parameter == "category" then
		where = ("category='%s'"):format(search_value)
	elseif search_parameter == "type" then
		table.insert(tables, "EnemyStats2Types=F")
		table.insert(join_keys, "S.name=F.name")
		where = ("F.type='%s'"):format(search_value)
	elseif search_parameter == "region" then
		where = ("region='%s'"):format(search_value)
	else
		-- invalid filter
		return
	end

	local enemies = Cargo.query(
		table.concat(tables, ","),
		table.concat(fields, ","),
		{
			groupBy="name",
			join=table.concat(join_keys, ","),
			orderBy=table.concat(order_keys, ","),
			where=where
		}
	)

	for _, enemy in ipairs(enemies) do
		Utils.parse_row(enemy, hs)
	end
	return enemies
end

local function fetch_all(args)
	local hs = Histogram._load_table("EnemyStats2Histograms")
	local enemies = {}
	for _, row in ipairs(args) do
		if #row >= 2 then
			local fetched = query(row[1], row[2], hs) or {}
			for _, enemy in ipairs(fetched) do
				table.insert(enemies, enemy)
			end
		end
	end
	return enemies
end

local function text_cell(label, sort_key)
	return mw.html.create("td")
		:attr("data-sort-value", sort_key)
		:addClass("ctr")
		:wikitext(label)
end

local function name_cell(enemy)
	local label = enemy.name
	if enemy.article ~= nil then
		label = ("[[%s|%s]]"):format(enemy.article, label)
	end
	if enemy.icon ~= nil then
		label = ("[[File:%s|40px]]<br>"):format(enemy.icon) .. label
	end
	return text_cell(label, enemy.name)
end

local function region_cell(enemy)
	local region = enemy.region
	if region == nil then
		return text_cell("''Any''", 0)
	elseif Regions[region] == nil then
		return text_cell(region, -1)
	end
	region = Regions[region]
	return text_cell(
		("[[%s]]"):format(region.article),
		region.sort_key
	)
end

local function types_cell(enemy)
	local type_links = {}
	for i, t in ipairs(enemy.types) do
		if Types[t] == nil then
			type_links[i] = t
		else
			type_links[i] = Types[t]:link()
		end
	end
	return text_cell(table.concat(type_links, "<br>"))
end

local function tiers_cell(enemy)
	local tiers = {}
	if enemy.is_boss == 1 then
		table.insert(tiers, "[[Bosses (Darkest Dungeon II)|Boss]]")
	end
	if enemy.champion_of ~= nil then
		table.insert(tiers, "Champion")
	end
	if enemy.minion_of ~= nil then
		table.insert(tiers, "Minion")
	end
	return text_cell(table.concat(tiers, "<br>"), enemy.tier_key)
end

local function _render(enemies)
	local res = mw.html.create("table")
		:addClass("tablebgdd2")
		:addClass("sortable")

	local header = res:tag("tr")
	header:tag("th")
		:wikitext("Enemy")
	header:tag("th")
		:wikitext("[[Regions|Region]]")
	header:tag("th")
		:wikitext("[[Enemy Type (Darkest Dungeon II)|Types]]")
	header:tag("th")
		:wikitext("Tiers")
	for _, stat in ipairs(Utils.STATS) do
		header:tag("th")
			:wikitext(stat:icon())
	end

	for _, enemy in ipairs(enemies) do
		local row = res:tag("tr")
			:attr("id", enemy.name)
		row:node(name_cell(enemy))
		row:node(region_cell(enemy))
		row:node(types_cell(enemy))
		row:node(tiers_cell(enemy))
		for _, stat in ipairs(Utils.STATS) do
			row:node(stat:render(enemy))
		end
	end

	return res
end

local function render(frame)
	local args = TableArguments.getArgs(frame)
	local enemies = fetch_all(args)
	return _render(enemies)
end

return {render=render}