Module:EnemyStats2/Table
This module defines a single function, query
(with both Lua and Wikitext variants) that renders a table for a subset of enemies. A few methods are currently supported for filtering out enemies:
type=...
for all enemies which have a specific type.category=...
for all enemies in a particular category. See Template:EnemyStats2 for more information about how categories are defined, or look at the table directly.region=...
returns all enemies that can appear in a region. This includes both enemies native to that region, along with enemies that can appear in any region.
If you don't specify any filters, it will create a table with all the enemies. This is what's currently done on Enemies (Darkest Dungeon II)/Stats.
Sorting Criteria
The sorting keys are a bit complicated. Each enemy has a category
, an attribute that exists only on the wiki for the purposes of sorting. Enemies are sorted in the following order:
- First they are sorted by their
category
. Eachcategory
has its own order, defined in the Special:CargoTables/EnemyStats2CategoryInfo table. - Then they are sorted by tier:
- Normal enemies appear first
- Then champion enemies
- Then minions (enemies that are only summoned by bosses or only appear in a boss fight). If an enemy is both a champion and a minion, it is considered a champion for sorting purposes.
- Bosses come last
- Then sorted by HP
- Then sorted in alphabetical order
Note that both tier and minion are terms that only appear on the wiki in order to make sorting easier—we'd like to group minions along with their bosses, and we'd like to put bosses at the bottom of the list. tier and minion do not appear anywhere in the game as far as I know.
Examples
type=creature
Searching by type often produces a lot of unwanted results so it's usually not the best way to get specific data.
Enemy | Region | Types | Tiers | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Mongrel | Any | Creature | 13 | 6 | 0 | 40% | 40% | 30% | 10% | 10% | 10% | |
Webber | Any | Creature | 12 | 5 | 0 | 10% | 60% | 30% | 10% | 10% | 10% | |
Rabid Gnasher | Any | Creature | 14 | 4 | 0 | 40% | 40% | 20% | 20% | 10% | 10% | |
Spitter | Any | Creature | 14 | 3 | 0 | 10% | 60% | 30% | 10% | 10% | 10% | |
Carrion Eater | Any | Creature | 17 | 1 | 0 | 10% | 40% | 20% | 20% | 10% | 10% | |
Carrion Devourer | Any | Creature | Champion | 23 | 2 | 1 | 20% | 60% | 30% | 20% | 30% | 10% |
Gander | Any | Creature | Champion | 23 | 2 | 2 | 75% | 40% | 20% | 40% | 30% | 20% |
Livestock | The Foetor | Creature | 14 | 1 | 0 | 10% | 50% | 20% | 30% | 10% | 10% | |
Black Phillip | The Foetor | Creature | Champion | 29 | 2 | 0 | 20% | 60% | 20% | 30% | 10% | 20% |
Swine Skulker | The Sluice | Creature | 15 | 4 | 0 | 20% | 40% | 30% | 10% | 20% | 10% | |
Swine Skiver | The Sluice | Creature | 20 | 3 | 0 | 30% | 40% | 20% | 20% | 20% | 20% | |
Swine Brute | The Sluice | Creature | 40 | 0 | 2 | 20% | 40% | 20% | 40% | 50% | 20% | |
Fulgore | The Sluice | Creature | Champion | 29 | 4 | 0 | 40% | 60% | 20% | 40% | 20% | 20% |
Wilbur | The Sluice | Creature | Champion | 48 | 0 | 3 | 20% | 40% | 20% | 50% | 50% | 30% |
category=creature_den
Here is the same table, but with enemies restricted to those that show up at the Creature Den.
Enemy | Region | Types | Tiers | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Webber | Any | Creature | 12 | 5 | 0 | 10% | 60% | 30% | 10% | 10% | 10% | |
Rabid Gnasher | Any | Cadaver, Creature | 14 | 4 | 0 | 40% | 40% | 20% | 20% | 10% | 10% | |
Spitter | Any | Creature | 14 | 3 | 0 | 10% | 60% | 30% | 10% | 10% | 10% | |
Carrion Eater | Any | Creature | 17 | 1 | 0 | 10% | 40% | 20% | 20% | 10% | 10% | |
Carrion Devourer | Any | Creature | Champion | 23 | 2 | 1 | 20% | 60% | 30% | 20% | 30% | 10% |
Gander | Any | Cadaver, Creature | Champion | 23 | 2 | 2 | 75% | 40% | 20% | 40% | 30% | 20% |
category=sluice
Enemies in The Sluice. This is actually identical to querying by type=swine
.
Enemy | Region | Types | Tiers | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Swine Skulker | The Sluice | Creature, Swine | 15 | 4 | 0 | 20% | 40% | 30% | 10% | 20% | 10% | |
Swine Skiver | The Sluice | Creature, Swine | 20 | 3 | 0 | 30% | 40% | 20% | 20% | 20% | 20% | |
Swine Brute | The Sluice | Creature, Swine | 40 | 0 | 2 | 20% | 40% | 20% | 40% | 50% | 20% | |
Fulgore | The Sluice | Creature, Swine | Champion | 29 | 4 | 0 | 40% | 60% | 20% | 40% | 20% | 20% |
Wilbur | The Sluice | Creature, Swine | Champion | 48 | 0 | 3 | 20% | 40% | 20% | 50% | 50% | 30% |
category=tangle
Enemies in The Tangle. We can't use type=cadaver
because that also gets Rabid Gnasher and Gander.
Enemy | Region | Types | Tiers | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Arbalist | The Tangle | Cadaver | 15 | 1 | 0 | 30% | 30% | 10% | 10% | 10% | 10% | |
Foot Soldier | The Tangle | Cadaver | 17 | 1 | 1 | 30% | 30% | 10% | 50% | 10% | 10% | |
Drummer | The Tangle | Cadaver | 19 | 5 | 0 | 30% | 30% | 10% | 30% | 10% | 20% | |
Bishop | The Tangle | Cadaver | 22 | 2 | 0 | 30% | 30% | 20% | 20% | 20% | 30% | |
Knight | The Tangle | Cadaver | 36 | 0 | 3 | 40% | 20% | 10% | 40% | 40% | 30% | |
Bullseye Barrett | The Tangle | Cadaver | Champion | 20 | 1 | 1 | 40% | 40% | 10% | 10% | 20% | 10% |
Fallen Templar | The Tangle | Cadaver | Champion | 41 | 2 | 3 | 50% | 30% | 10% | 40% | 40% | 30% |
Tap Root | The Tangle | None | Boss, Minion | Invulnerable | 10 | 0 | Immune | Immune | Immune | Immune | Immune | Immune |
Dreaming General | The Tangle | Cadaver | Boss | 185 | 3 | 2 | 50% | 30% | 20% | Immune | Immune | 40% |
local Cargo = mw.ext.cargo
local getArgs = require("Module:Arguments").getArgs
local Histogram = require("Module:Histogram")
local Utils = require("Module:EnemyStats2/Utils")
local LINK_LABEL = '[[%s|%s]]<i id="%s"></i>'
local REGIONS = {
valley={article="The Valley", sort_key="0"},
sprawl={article="The Sprawl", sort_key="10"},
tangle={article="The Tangle", sort_key="11"},
foetor={article="The Foetor", sort_key="12"},
shroud={article="The Shroud", sort_key="13"},
sluice={article="The Sluice", sort_key="20"},
mountain={article="The Mountain", sort_key="30"}
}
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 = LINK_LABEL:format(enemy.article, enemy.name, enemy.name)
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)
if enemy.region == nil then
return text_cell("''Any''", -1)
end
return text_cell(
("[[%s]]"):format(REGIONS[enemy.region].article),
REGIONS[enemy.region].sort_key
)
end
local function types_cell(enemy)
local type_links = Utils._type_links(enemy)
return text_cell(table.concat(type_links, ",<br>"))
end
local function tiers_cell(enemy)
local tiers = {}
if enemy.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 fetch_data(where)
local tables = {
"EnemyStats2",
"EnemyStats2Types",
"EnemyStats2CategoryInfo",
}
local fields = {
"EnemyStats2.name=name",
"icon",
"article",
"boss",
"champion_of",
"minion_of",
-- Cargo doesn't support CASE statements?
[[IF(boss=1, 4,
IF(champion_of IS NOT NULL, 2,
IF(minion_of IS NOT NULL, 3,
1
)))=tier_key]],
"region",
"GROUP_CONCAT(type ORDER BY type SEPARATOR ' ')=types"
}
for _, stat in ipairs(Utils.STATS) do
table.insert(fields, stat.name)
end
local join_keys = {
"EnemyStats2.name=EnemyStats2Types.name",
"EnemyStats2.category=EnemyStats2CategoryInfo.category"
}
local order_keys = {
"sort_key",
"tier_key",
"hp",
"name",
}
local enemies = Cargo.query(
table.concat(tables, ","),
table.concat(fields, ","),
{
groupBy="name",
join=table.concat(join_keys, ","),
orderBy=table.concat(order_keys, ","),
where=where
}
)
local hs = Histogram._load_table("EnemyStats2Histograms")
for i, enemy in ipairs(enemies) do
Utils._parse_enemy(enemy)
for _, stat in ipairs(Utils.STATS) do
enemy[stat.name .. "_cdf"] = Histogram._interpolate_cdf(
hs[stat.name], enemy[stat.name])
end
end
return enemies
end
local function _query(args)
local where = nil
if args.category ~= nil then
where = ("EnemyStats2.category='%s'"):format(args.category)
elseif args.type ~= nil then
where = ("EnemyStats2Types.type='%s'"):format(args.type)
elseif args.region ~= nil then
where = ("region IS NULL OR region='%s'"):format(args.region)
end
local enemies = fetch_data(where)
local result = mw.html.create("table")
:addClass("tablebgdd2")
:addClass("sortable")
local header = result: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:short_label())
end
for _, enemy in ipairs(enemies) do
local row = result:tag("tr")
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:create_cell(enemy))
end
end
return result
end
local function query(frame)
return _query(getArgs(frame))
end
return {
_query=_query,
query=query,
}