Module:Spawn table

Jump to navigation Jump to search

This module implements Template:Spawn table.

Dependencies[edit source]

[view] [edit] [history] [refresh]The above documentation is transcluded from Module:Spawn table/doc.
require('strict')
local p = {}
local pageTitle = mw.title.getCurrentTitle()
local pageTitleString = pageTitle.fullText
local namespace = pageTitle.nsText

local function tooltip(text, title)
	return tostring(mw.html.create('span')
		:addClass('explain')
		:attr('title', title)
		:wikitext(text)
	:allDone())
end

local i18n = {
	processArgsModule = 'Module:ProcessArgs',
	mobColumn = 'Mob',
	chanceColumn = tooltip('Spawn weight', 'Weight relative to other spawn entries in the category'),
	groupSizeColumn = tooltip('Group size', 'Number of mobs the game tries to spawn per attempt'),
	chargeColumn = tooltip('Charge', 'Charge generated by the mob'),
	budgetColumn = tooltip('Budget', 'Maximum charge potential allowing spawning'),
	spawnCostNote = 'When spawning a mob with a budget, take the sum of the charge of each existing mob divided by the distance to that mob. If the total times the new mob\'s charge is greater than the new mob\'s budget, the spawn fails. See [[Mob spawning#Spawn costs|Mob spawning § Spawn costs]] for details.',
	
	-- SMW properties
	smwSubnamePrefix = "SPAWN",
	smwSpawnedMob = "Spawned mob",
	smwSpawnedIn = "Spawned in",
	smwEdition = "Edition",
	smwCategory = "Category",
	smwWeight = "Weight",
	smwTotalWeight = "Total weight",
	smwSize = "Size",
	smwNote = "Note",
	smwNoteName = "Note name",
	smwSpawnJSON = "Spawn JSON"
}

local groupArgs = {
	['creature'] = 'Creature category',
	['passive'] = 'Creature category', --Deprecated
	['monster'] = 'Monster category',
	['hostile'] = 'Monster category', --Deprecated
	['ambient'] = 'Ambient category',
	['axolotl'] = 'Axolotl category',
	['watercreature'] = 'Water creature category',
	['underground'] = 'Underground water creature category',
	['waterambient'] = 'Water ambient category',
	['misc'] = 'Misc category'
}

-- [[Template:Spawn row]]
function p.main(frame)
	local args = frame
	if frame == mw.getCurrentFrame() then
		args = require(i18n.processArgsModule).merge( true )
	else
		frame = mw.getCurrentFrame()
	end
	
	local data = {
		mob = args.name or args[1],
		weight = args.weight,
		size = args.size,
		charge = args.charge,
		budget = args.budget,
		note = args.note,
		notename = args.notename
	}
		
	return mw.text.jsonEncode(data)
end

-- parses input arguments into spawnData table
local function parseInput(args)
	local spawnData = {}
	spawnData.notes = {}
	
	for argName in pairs(groupArgs) do
		if args[argName] and args[argName] ~= "" then
			local group = {}
			group.category = argName
			group.mobs = {}
			group.totalWeight = 0
			
			-- parse input of group parameter
			for line in mw.text.gsplit(args[argName], '\n') do  -- split on newline
				local parsed = mw.text.jsonDecode(line)
				
				if parsed.weight and tonumber(parsed.weight) then
					parsed.weight = tonumber(parsed.weight)
					group.totalWeight = group.totalWeight + parsed.weight
				end

				if parsed.charge or parsed.budget then
					spawnData.hasSpawnCost = true
				end
				
				if parsed.note or parsed.notename then
					spawnData.hasNotes = true
					
					if not parsed.notename then
						parsed.notename = parsed.mob
					end
					
					if parsed.note and parsed.notename then
						spawnData.notes[parsed.notename] = parsed.note
					end
				end
				
				if parsed.mob then
					table.insert(group.mobs, parsed)
				end
			end
			table.insert(spawnData, group)
			
			-- Put data into SMW
			local onMain = false
			if (namespace == '' or namespace == mw.site.namespaces[4].name) then
				onMain = true
			end
			if onMain and not args.ignoreusage then
				for _, data in ipairs(group.mobs) do
					local origMob = data.mob
						:gsub("Warm ", "")
						:gsub("Cold ", "")
						:gsub("Ashen ", "")
						:gsub("Black ", "")
						:gsub("Chestnut ", "")
						:gsub("Pale ", "")
						:gsub("Rusty ", "")
						:gsub("Snowy ", "")
						:gsub("Spotted ", "")
						:gsub("Striped ", "")
						:gsub("Woods ", "")
					
					local smw_sub = {}
					local smwSpawnedIn = pageTitleString
					
					local subname = i18n.smwSubnamePrefix .. '_' .. origMob
					local smw_json = {
						[i18n.smwSpawnedMob] = data.mob,
						[i18n.smwSpawnedIn] = smwSpawnedIn,
						[i18n.smwEdition] = (args.edition or 'java'):lower(),
						[i18n.smwCategory] = groupArgs[argName]:gsub(' category', ''),
						[i18n.smwWeight] = data.weight,
						[i18n.smwTotalWeight] = group.totalWeight,
						[i18n.smwSize] = data.size,
						[i18n.smwNote] = data.note or spawnData.notes[data.notename],
						[i18n.smwNoteName] = data.notename
					}
					
					local smw_sub = { -- the actual SMW sub-object
						[i18n.smwSpawnedMob] = origMob,
						[i18n.smwSpawnedIn] = smwSpawnedIn,
						[i18n.smwSpawnJSON] = mw.text.jsonEncode(smw_json)
					}
					mw.smw.subobject(smw_sub, subname)
				end
			end
		end
	end
	
	return spawnData
end

local function addTableBody(spawnData, colspan)
	local ret = mw.html.create()
	for _, groupTable in ipairs(spawnData) do
		ret:tag('tr')
			:tag('th')
				:attr('colspan', colspan)
				:wikitext(groupArgs[groupTable.category])
			:done()
		:done()
		
		for _, mobData in ipairs(groupTable.mobs) do
			ret:tag('tr')
			
			local mobCellText = require('Module:SpriteFile').link{name = 'EntitySprite', mobData.mob}
			
			if mobData.note or mobData.notename then 
				mobCellText = mobCellText .. mw.getCurrentFrame():extensionTag{name='ref', content=mobData.note, args={name=mobData.notename or mobData.mob, group='note'}}
			end
			
			ret:tag('th')
				:css('text-align', 'left')
				:css('font-weight', 'normal')
				:wikitext(mobCellText)
			:done()
			
			-- Simplify weights for pools with single entries to avoid confusion from e.g. 10/10 and 25/25
			local weightText = '1'
			if mobData.weight ~= groupTable.totalWeight then
				weightText = '<sup>' .. mobData.weight .. '</sup>&frasl;<sub>' .. groupTable.totalWeight .. '</sub>'
		    end
			
			ret:tag('td')
				:css('text-align', 'center')
				:wikitext(weightText)
			:done()
			:tag('td')
				:css('text-align', 'center')
				:wikitext((mobData.size:gsub('-', '&ndash;')))
			:done()

			if spawnData.hasSpawnCost then
				ret:tag('td')
					:css('text-align', 'center')
					:wikitext(mobData.charge)
				:done()
				:tag('td')
					:css('text-align', 'center')
					:wikitext(mobData.budget)
				:done()
			end

			ret:done()
		end
	end
	
	return ret
end

-- [[Template:Spawn table]]
function p.mobSpawnTable(frame)
	local args = frame
	if frame == mw.getCurrentFrame() then
		args = require(i18n.processArgsModule).merge( true )
	else
		frame = mw.getCurrentFrame()
	end
	
	local spawnData = parseInput(args)

	local columns = {i18n.mobColumn, i18n.chanceColumn, i18n.groupSizeColumn}
	
	local tableRoot = mw.html.create('table')
		:addClass('wikitable')
	
	if spawnData.hasSpawnCost then
		spawnData.hasNotes = true
		table.insert( columns, i18n.chargeColumn .. frame:extensionTag{name='ref', content=i18n.spawnCostNote, args={name='spawn-cost', group='note'}} )
		table.insert( columns, i18n.budgetColumn .. frame:extensionTag{name='ref', args={name='spawn-cost', group='note'}} )
	end
	
	local titleStr = args.title
	if args.edition then
		local editionStr = string.format("'''''[[%s Edition]]'''''", (args.edition or ''):lower() == 'bedrock' and 'Bedrock' or 'Java')
		if titleStr then
			titleStr = titleStr .. ' in ' .. editionStr
		else
			titleStr = 'In ' .. editionStr
		end
	end
	
	if titleStr then
		tableRoot:tag('caption')
			:wikitext(titleStr)
		:done()
	end
	
	tableRoot:tag('tr')
	for _, value in ipairs(columns) do
		tableRoot:tag('th')
			:wikitext(value)
		:done()
	end
	tableRoot:done()
		:node(addTableBody(spawnData, #columns))
	:allDone()
	
	local refs = ''
	if spawnData.hasNotes then
		refs = '\n\n' .. frame:extensionTag{name='references', args={group='note'}}
	end
	
	return tostring(tableRoot) .. refs .. require('Module:NiceJSON').wrap(spawnData, 'pre', 'spawntable-json')
end

return p