Module:Weapons/infobox

From Soulframe Wiki
Jump to navigation Jump to search

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

---	'''Weapons/infobox''' builds the infobox on weapon pages and adds the 
--	appropriate category pages.<br />
--
--	@module		Weapons/infobox
--	@alias		p
--	@author			[[User:FINNER|FINNER]]
--	@attribution	[[User:Gigamicro|Gigamicro]]
--	@attribution	[[User:Scientia|Scientia]]
--	@image		
--	@require	[[Module:InfoboxBuilder]]
--	@require	[[Module:Table]]
--	@require	[[Module:Vendors]]
--	@require	[[Module:Weapons]]
--	@require	[[Module:Weapons/data]]
--	@release	stable
--	<nowiki>

local InfoboxBuilder = require([[Module:InfoboxBuilder]])
local Table = require([[Module:Table]])
local Vendors = require([[Module:Vendors]])
local Weapons = require([[Module:Weapons]])
local WeaponsData = require([[Module:Weapons/data]])

local p = {}

--- Builds the weapon infobox.
--	@function	p.buildInfobox
--	@param		{table} frame Frame object
--	@return		{string} Wikitext of infobox
function p.buildInfobox(frame)
	local args = frame.args
	local name = mw.text.decode(args['Name'])
	local weapon = Table.deepCopy(WeaponsData[name])	-- Want to make table not read-only to set metamethods
	
	assert(weapon ~= nil, ('p.buildInfobox(frame): weapon with name "%s" does not exist in %s')
		:format(name, '[[Module:Weapons/data]]'))
	
	-- Creating a wrapper function to get formatted value for a particular stat
	-- by simplying calling weapon entry (e.g. weapon('BaseDamage') or weapon('FireRate', 2))
	setmetatable(weapon,
		{
			__call = function(self, statKey, attackIndex)
				if (attackIndex ~= nil) then
					return Weapons._getFormattedValue(self, statKey, attackIndex) or nil
				end
				-- TODO: Ideally, we should be able to instantiate a new weapon entry object
				-- via M:Weapons so we can just directly use that object's _getFormattedValue
				-- instead of treating Weapon as a static class and also passing in entry table
				return Weapons._getFormattedValue(self, statKey, self._TooltipAttackDisplay) or nil
			end
		}
	)

	local Infobox = InfoboxBuilder('Soulframe Wiki:L10n/weapons.json', 'Soulframe Wiki:L10n/general.json', 'Soulframe Wiki:L10n/meta.json')
	:tag('title')
		:tag('default')
			:tag('b'):wikitext(name):done()
		:done()
	:done()
	:tag('image'):attr('source', 'Image')
		:tag('default'):wikitext(weapon.Image or 'UnidentifiedItem.png'):done()
	:done()
	:group()
		:caption('UpdateInfoboxData', '[[Module:Weapons/data|📝 %s]]', 'update-infobox-data')
	:done()
	:header('%s', 'general-information')
	:row('Skills', '%s', weapon('Skill'), 'skills')
	:row('Attune', '%s', weapon('Attune'), 'attune')
	:row('Level',	'%s', weapon('Level'), 'level')
	:row('Slot', '[[File:TopWeapon.png|x18px|link=Weapons]] [[Weapons|%s]]', weapon('Slot'), 'slot')
	
	:group():header('%s', 'utility')
		:row('AttackSpeed', '[[Attack Speed|%s]]', weapon('AttackSpeed', 1) or nil, 'attack-speed')
		:row('BlockAngle', '[[Melee#Blocking|%s]]', weapon.BlockAngle and weapon('BlockAngle'), 'block-angle')
		:row('FollowThrough', '[[Melee#Follow_Through|%s]]', weapon.FollowThrough and weapon('FollowThrough'), 'follow-through')
		:row('MeleeRange', '[[Melee#Range|%s]]', weapon.MeleeRange and weapon('MeleeRange'), 'range')
		:row('NoiseLevel', '[[Noise Level|%s]]', weapon.Attacks[1].IsSilent and 'Silent' or 'Alarming', 'noise-level')
	:done()
	
	-- Weapon attack sections
	local horiz, elems, attack
	for i, attackEntry in ipairs(weapon.Attacks) do
		attack = 'Attack'..i
		elems = {}
		for dt, dmg in pairs(attackEntry.Damage) do
			if dt ~= 'Sharp' then -- and dt ~= 'Puncture' and dt ~= 'Slash' then
				table.insert(elems, dt)
			end
		end
		
		-- Displaying IPS damage types first to match in-game presentation
		horiz = mw.html.create('group'):attr('layout', 'horizontal')
		local damageFormatString = '%s<br />(%s)'
		
		horiz:row(attack..'Sharp', nil, attackEntry.Damage.Sharp and 
				damageFormatString:format(weapon('Sharp', i), weapon('SharpDistribution', i)), 'sharp')
			-- :row(attack..'Puncture', nil, attackEntry.Damage.Puncture and 
			-- 	damageFormatString:format(weapon('Puncture', i), weapon('PunctureDistribution', i)), 'puncture')
			-- :row(attack..'Slash', nil, attackEntry.Damage.Slash and 
			-- 	damageFormatString:format(weapon('Slash', i), weapon('SlashDistribution', i)), 'slash')
		
		for _, elem in ipairs(elems) do
			horiz:row(attack..elem, nil, attackEntry.Damage[elem] and 
				damageFormatString:format(weapon(elem, i), weapon(elem..'Distribution', i)), elem)
		end
		
		Infobox:group():header(weapon('AttackName', i) or name)
			:node(horiz)
			:row(attack..'Total', '[[Damage|%s]]', weapon('TotalDamage', i)..' ('..weapon('DamageBias', i)..')', 'total-damage')
			-- A melee weapon's index 1 attack should always be a normal melee sweep
			-- :row(attack..'AttackSpeed', '[[Attack Speed|%s]]', attackEntry.AttackSpeed and weapon('AttackSpeed', i), 'attack-speed')
			:row(attack..'MortalChance', '[[Mortal Blow|%s]]', weapon('MortalChance', i), 'mortal-chance')
			-- :row(attack..'ForcedProcs', '[[Status Effect|%s]]', attackEntry.ForcedProcs and weapon('ForcedProcs', i), 'forced-procs')
			-- :row(attack..'HeadshotMultiplier', '%s', attackEntry.HeadshotMultiplier and weapon('HeadshotMultiplier', i), 'headshot-multiplier')
			:row(attack..'NoiseLevel', '[[Noise Level|%s]]', attackEntry.IsSilent and 'Silent' or 'Alarming', 'noise-level')
			-- :row(attack..'Range', '[[Range|%s]]', attackEntry.Range and weapon('Range', i), 'range')
			-- :row(attack..'StatusChance', '[[Status Chance|%s]]', attackEntry.StatusChance and weapon('StatusChance', i), 'status-chance')
		:done()
	end
	
	-- Infobox:group():header('%s', 'heavy-attack')
	-- 	:row('HeavyAttack', '[[Melee#Heavy Attack|%s]]', weapon.HeavyAttack and weapon('HeavyAttack'), 'heavy-damage')
	-- 	:row('HeavySlamAttack', '[[Melee#Heavy Attack|%s]]', weapon.HeavySlamAttack and weapon('HeavySlamAttack'), 'slam-damage')
	-- 	:row('HeavyRadialDmg', '%s', weapon.HeavyRadialDmg and weapon('HeavyRadialDmg'), 'radial-damage')
	-- 	:row('HeavySlamRadius', '%s', weapon.HeavySlamRadius and weapon('HeavySlamRadius'), 'slam-radius')
	-- 	:row('WindUp', '[[Melee#Heavy Attack|%s]]', weapon.WindUp and weapon('WindUp'), 'wind-up')
	-- :done()
	
	-- :group():header('%s', 'slam-attack')
	-- 	:row('SlamAttack', '[[Melee#Slam Attack|%s]]', weapon.SlamAttack and weapon('SlamAttack'), 'slam-damage')
	-- 	:row('SlamRadius', '%s', weapon.SlamRadius and weapon('SlamRadius'), 'slam-radius')
	-- 	:row('SlamRadialDamage', '%s', weapon.SlamRadialDmg and weapon('SlamRadialDmg'), 'radial-damage')
	-- 	:row('SlamRadialElement', '%s', weapon.SlamRadialElement and weapon('SlamRadialElement'), 'slam-radial-element')
	-- 	:row('SlamRadialProcs', '%s', weapon.SlamRadialProcs and weapon('SlamRadialProcs'), 'radial-forced-proc')
	-- :done()
	
	-- :group():header('%s', 'slide-attack')
	-- 	:row('SlideAttack', '[[Melee#Slide Attack|%s]]', weapon.SlideAttack and weapon('SlideAttack'), 'slide-damage')
	-- 	:row('SlideElement', '%s', weapon.SlideElement and weapon('SlideElement'), 'slide-element')
	-- :done()
	
	Infobox:group():header('%s', 'miscellaneous')
		:row('Family', '%s', weapon.Family, 'family')
		:row('Introduced', '%s', weapon.Introduced and weapon('Introduced'), 'introduced')
		-- :row('SellPrice', '%s', weapon.SellPrice and weapon('SellPrice'), 'sell-price')
		:row('Users', '%s', weapon.Users and weapon('Users'), 'users')
		:row('Variants', '%s', weapon.Family and weapon('FamilyList'), 'variants')
	:done()
	
	local vendorStr = Vendors._buildVendorSourceStrings(name)
	
	Infobox:group():header('%s', 'vendor-sources')
		:tag('data'):attr('source', 'Offerings')
			:tag('default')
				:tag('div'):addClass('tabber-borderless')
					:wikitext(('<tabber>%s</tabber>'):format(
					(vendorStr ~= '') and '|-|Vendors='..vendorStr..'\n' or ''
				)):done()
			:done()
		:done()
	:done()
	:group():header('%s', 'article-categories')
		:tag('data'):attr('source', 'Categories')
			:tag('default')
				:tag('div')
					:wikitext(Weapons._statFormat(weapon, 1, 'Categories'))
				:done()
		:done()
	:done()
	
	return frame:preprocess(tostring(Infobox))
end

return p