Module:Enemy List

Revision as of 13:58, 2 January 2025 by Alsang (talk | contribs) (search will now include versions of monsters that have versions, and only display the default version, using the name of the overall monster and not the specific version)
Module documentation
This documentation is transcluded from Module:Enemy List/doc. [edit] [history] [purge]
This module does not have any documentation. Please consider adding documentation at Module:Enemy List/doc. [edit]
Module:Enemy List's function main is invoked by Template:EnemyList.
Module:Enemy List requires Module:Array.
Module:Enemy List requires Module:Purge.
Module:Enemy List requires Module:Yesno.
Module:Enemy List requires strict.
Module:Enemy List loads data from Module:Experience/data.

require('strict')
local yesno = require('Module:Yesno')
local album_xp_data = mw.loadData('Module:Experience/data').album
local Array = require('Module:Array')
local lang = mw.language.getContentLanguage()
local purge = require('Module:Purge')._purge

local function formatNum(n)
	if n == nil then
		return ''
	end
	return lang:formatNum(n)
end

local p = {}

function p.main(frame)
	local args = frame:getParent().args
	local profession = args.profession or mw.title.getCurrentTitle()
	local passive = yesno(args.passive) and true or false
	return p._main(profession, passive)
end

-- Similar to Template:AttackStyle
local function format_attack_style(style)
	style = (style or ''):lower()
	if style == '' then
		return "''Unknown''"
	end
	if style == 'none' then
		return "''None''"
	end
	style = style:sub(1,1):upper() .. style:sub(2)
	return ('[[File:%s damage icon.png|18x18px|link=%s]] [[%s]]'):format(style, style, style)
end

local function active_table(data)
	local out = mw.html.create('table')
		:addClass('wikitable sortable align-center-3 align-center-4')
		:tag('caption')
			:wikitext('This list is updated dynamically. '..purge())
		:done()
		:tag('tr')
			:tag('th')
				:attr{ colspan = '2' }
				:wikitext('Enemy')
			:done()
			:tag('th'):wikitext('Unlock<br>Level'):done()
			:tag('th'):wikitext('Combat<br>Level'):done()
			:tag('th'):wikitext('HP'):done()
			:tag('th'):wikitext('Attack Style'):done()
			:tag('th'):wikitext('Immune To'):done()
			:tag('th'):wikitext('Vulnerable'):done()
			:tag('th'):wikitext('Found At'):done()
			:tag('th'):wikitext('XP'):done()
			:tag('th'):wikitext('Album XP'):done()
		:done()

	for _, monster in ipairs(data) do
		local row = out:tag('tr')
			:tag('td'):wikitext(monster.Image):done()
			:tag('td'):wikitext(('[[%s]]'):format(monster['Name'])):done()
			:tag('td'):wikitext(monster['Unlock level']):done()
			:tag('td'):wikitext(monster['Profession Level A']):done()
			:tag('td'):wikitext(formatNum(monster.Health)):done()
			:tag('td'):wikitext(format_attack_style(monster['Attack style'])):done()
			:tag('td'):wikitext(format_attack_style(monster['Immune to'])):done()
			:tag('td'):wikitext(format_attack_style(monster['Vulnerable to'])):done()

		local location_text = {}
		for location, qty in pairs(monster['Location JSON']) do
			table.insert(location_text, ('[[%s]] (%s)'):format(location, qty == -1 and '?' or qty))
		end
		row
			:tag('td'):wikitext(table.concat(location_text, ', ')):done()
			:tag('td'):wikitext(formatNum(monster.Experience)):done()
			:tag('td'):wikitext(formatNum(monster['Album XP'])):done()
	end

	return out
end

local function passive_table(data)
	local out = mw.html.create('table')
		:addClass('wikitable sortable align-center-3 align-center-4 align-center-5')
		:tag('tr')
			:tag('th')
				:attr{ colspan = '2' }
				:wikitext('Enemy')
			:done()
			:tag('th'):wikitext('Level'):done()
			:tag('th'):wikitext('Weapon<br>Strength'):done()
			:tag('th'):wikitext('[[File:Knowledge icon.png|16px|link=Knowledge]] KP'):done()
			:tag('th'):wikitext('Location'):done()
			:tag('th'):wikitext('XP'):done()
			:tag('th'):wikitext('Album XP'):done()
		:done()

	for _, monster in ipairs(data) do
		local row = out:tag('tr')
			:tag('td'):wikitext(monster.Image):done()
			:tag('td'):wikitext(('[[%s]]'):format(monster['Name'])):done()
			:tag('td'):wikitext(monster['Unlock level']):done()
			:tag('td'):wikitext(monster['Unlock level'] and monster['Unlock level'] + 20):done()
			:tag('td'):wikitext(monster.Knowledge):done()

		local location_text = {}
		for location, qty in pairs(monster['Location JSON']) do
			-- Quantity unimportant
			table.insert(location_text, ('[[%s]]'):format(location))
		end
		row
			:tag('td'):wikitext(table.concat(location_text, ', ')):done()
			:tag('td'):wikitext(formatNum(monster.Experience)):done()
			:tag('td'):wikitext(formatNum(monster['Album XP'])):done()
	end

	return out
end

function p._main(profession, passive)
	local data = mw.smw.ask{
		'[[Infobox::Monster]]',
		('[[Profession A::%s]]'):format(profession),
		('[[Passive::%s]]'):format(passive and 'true' or 'false'),
		'?Image#70px;x70px',
		'?Unlock level',
		'?Profession Level A',
		'?Health',
		'?Attack style',
		'?Immune to',
		'?Vulnerable to',
		'?Location JSON',
		'?Experience',
		'?Quest',
		'?Name',
		'?Knowledge',
		'?Variant of#-',
		'?Version anchor',
		'?Version default',
		'sort=Profession Level A',
		'order=asc',
		'limit=500'
	}

	data = Array.filter(data, function(monster)
		return monster.Quest == nil and monster[1] ~= '[[:Training Dummy|Training Dummy]]' and ( monster['Version default'] or not(monster['Version anchor'] or false) )
	end)

	local location_cache = {}

	for _, monster in ipairs(data) do
		monster['Album XP'] = album_xp_data[monster['Profession Level A']]
		if monster['Location JSON'] == nil and monster['Variant of'] ~= nil then
			local variant_cat = monster['Variant of']
			if location_cache[variant_cat] == nil then
				local of_variant = mw.smw.ask{
					'[['..variant_cat..']]',
					'?Location JSON'
				}
				location_cache[variant_cat] = of_variant and of_variant[1]['Location JSON']
			end
			monster['Location JSON'] = location_cache[variant_cat]
		end
		monster['Location JSON'] = mw.text.jsonDecode(monster['Location JSON'] or '{}')
	end

	if passive then
		return passive_table(data)
	end
	return active_table(data)
end

return p