Module:Sandbox/User:Riblet15/Infobox Bonuses

From Old School RuneScape Wiki
Jump to: navigation, search
Module documentation
This documentation is transcluded from Template:Module sandbox/doc. [edit] [history] [purge]
Module:Sandbox/User:Riblet15/Infobox Bonuses requires Module:Attack speed bar.
Module:Sandbox/User:Riblet15/Infobox Bonuses requires Module:Clean image2.
Module:Sandbox/User:Riblet15/Infobox Bonuses requires Module:Format eq stat.
Module:Sandbox/User:Riblet15/Infobox Bonuses requires Module:Infobox.
Module:Sandbox/User:Riblet15/Infobox Bonuses requires Module:Mainonly.

This module is a sandbox for Riblet15. It can be used to test changes to existing modules, prototype new modules, or just experimenting with lua features.

Invocations of this sandbox should be kept in userspace; if the module is intended for use in other namespaces, it should be moved out of the sandbox into a normal module and template.

This default documentation can be overridden by creating the /doc subpage of this module, as normal.

--------------------------
-- Module for [[Template:Infobox Bonuses]]
------------------------
local p = {}

local onmain = require('Module:Mainonly').on_main
local infobox = require('Module:Infobox')
local attack_speed_bar = require('Module:Attack speed bar').make_bar
local signed = require('Module:Format eq stat').signed
local clean = require('Module:Clean image2').clean

local slots = {
	head = 'Head slot items',
	weapon = 'Weapon slot items',
	body = 'Body slot items',
	legs = 'Legs slot items',
	shield = 'Shield slot items',
	cape = 'Cape slot items',
	['2h'] = 'Two-handed slot items',
	hands = 'Hands slot items',
	feet = 'Feet slot items',
	neck = 'Neck slot items',
	ammo = 'Ammunition slot items',
	ring = 'Ring slot items',
}

function p.main(frame)
	local args = frame:getParent().args
	
	return p._main(args)
end

function p._main(args)
	local ret = infobox.new(args)

	local signed_numeric_args = {
		'astab', 'aslash', 'acrush', 'amagic', 'arange',
		'dstab', 'dslash', 'dcrush', 'dmagic', 'drange',
		'str', 'rstr', 'prayer'
	}

	for _, v in ipairs(signed_numeric_args) do
		ret:defineParams{
			{ name = v, func = { name = signednumericarg, params = { v, v }, flag = { 'd', 'r' } } },
			{ name = v..'_smw', func = { name = numericarg_smw, params = { v } } },
		}
	end

	ret:defineParams{
		{ name = 'mdmg', func = { name = signedpercentnumericarg, params = { 'mdmg', 'mdmg' }, flag = { 'd', 'r' } } },
		{ name = 'mdmg_smw', func = { name = numericarg_smw, params = { 'mdmg' }, flag = { 'p' } } },
		{ name = 'slot', func = 'has_content' },
		{ name = 'slot_image', func = { name = slotarg, params = { 'slot' } } },
		{ name = 'slot_link', func = { name = slot_link_arg, params = { 'slot' } } },
		{ name = 'speed', func = attack_speed_bar },
		{ name = 'speed_smw', func = { name = speedargsmw, params = { 'speed' }, flag = { 'p' } } },
		{ name = 'attackrange', func = attackrangearg },
		{ name = 'attackrange_smw', func = { name = attackrangeargsmw, params = { 'attackrange' }, flag = { 'p' } } },
		{ name = 'combatstyle', func = 'has_content' },
		{ name = 'image', func = { name = imagearg, params = { 'image', 'caption', 'image' }, flag = { 'd', 'd', 'r' } } },
		{ name = 'image_width', func = { name = image_width_arg, params = { 'image', 'image' }, flag = { 'd', 'r' } } },
		{ name = 'altimage', func = { name = imagearg, params = { 'altimage', 'altcaption', 'altimage' }, flag = { 'd', 'd', 'r' } } },
		{ name = 'altimage_width', func = { name = image_width_arg, params = { 'altimage', 'altimage' }, flag = { 'd', 'r' } } },
	}

	ret:defineLinks({ hide = true })

	local smw_mapping = {
		astab_smw = 'Stab attack bonus',
		aslash_smw = 'Slash attack bonus',
		acrush_smw = 'Crush attack bonus',
		arange_smw = 'Range attack bonus',
		amagic_smw = 'Magic attack bonus',
		dstab_smw = 'Stab defence bonus',
		dslash_smw = 'Slash defence bonus',
		dcrush_smw = 'Crush defence bonus',
		drange_smw = 'Range defence bonus',
		dmagic_smw = 'Magic defence bonus',
		str_smw = 'Strength bonus',
		rstr_smw = 'Ranged Strength bonus',
		prayer_smw = 'Prayer bonus',
		mdmg_smw = 'Magic Damage bonus',
		slot = 'Equipment slot',
		speed_smw = 'Weapon attack speed',
		attackrange_smw = 'Weapon attack range',
		combatstyle = 'Combat style',
	}

	local smw_all_mapping = {}
	for param, smw_name in pairs(smw_mapping) do
		smw_all_mapping[param] = 'All '..smw_name
	end

	ret:useSMWSubobject(smw_mapping)
	ret:useSMWOne(smw_all_mapping)

	ret:create()
	ret:cleanParams()

	local any_is_weapon = ret:paramGrep('slot', function(x) return infobox.isDefined(x) and (string.lower(x) == 'weapon' or string.lower(x) == '2h') end)

	ret:customButtonPlacement(true)
	ret:addButtonsCaption()

	ret:defineName('Infobox Bonuses')
	ret:addClass('infobox-bonuses infobox-bonuses-sandbox infobox')

	local image_rowspan = 15
	if any_is_weapon then
		image_rowspan = 19
	end

	local first_row = {
		{ tag = 'th', content = '[[File:Attack icon.png|link=Equipment Stats#Attack bonuses]] [[Equipment Stats#Attack bonuses|Attack bonuses]]', colspan = '10', class = 'infobox-subheader' }
	}

	local all_widths = ret:param('image_width', 'f')
	local altall_widths = ret:param('altimage_width', 'f')
	local max_width = math.max(max_width(all_widths), max_width(altall_widths))
	local image_defined = ret:paramGrep('image', function(x) return (infobox.isDefined(x) and x or 'N/A') ~= 'N/A' end)
	if image_defined then
		local image_td = { tag = 'argd', content = 'image', class = 'infobox-bonuses-image render-m', css = {width = max_width..'px'}, rowspan = image_rowspan }
		table.insert(first_row, image_td)
	end
	local altimage_defined = ret:paramGrep('altimage', function(x) return (infobox.isDefined(x) and x or 'N/A') ~= 'N/A' end)
	if altimage_defined then
		local altimage_td = { tag = 'argd', content = 'altimage', class = 'infobox-bonuses-image render-f', css = {width = max_width..'px'}, rowspan = image_rowspan }
		table.insert(first_row, altimage_td)
	end

	ret:addRow(first_row)
	:pad(10)
	:addRow{
		{ tag = 'th', content = '[[File:White dagger.png|link=Stab]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:White scimitar.png|link=Slash]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:White warhammer.png|link=Crush]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:Magic icon.png|link=Magic]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:Ranged icon.png|link=Ranged]]', colspan = '2', class = 'infobox-nested' }
	}
	:addRow{
		{ tag = 'argd', content = 'astab', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'aslash', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'acrush', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'amagic', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'arange', colspan = '2', class = 'infobox-nested' }
	}
	:pad(10)
	:addRow{
		{ tag = 'th', content = '[[File:Defence icon.png|link=Equipment Stats#Defence bonuses]] [[Equipment Stats#Defence bonuses|Defence bonuses]]', colspan = '10', class = 'infobox-subheader' }
	}
	:pad(10)
	:addRow{
		{ tag = 'th', content = '[[File:White dagger.png|link=Stab]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:White scimitar.png|link=Slash]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:White warhammer.png|link=Crush]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:Magic icon.png|link=Magic]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:Ranged icon.png|link=Ranged]]', colspan = '2', class = 'infobox-nested' }
	}
	:addRow{
		{ tag = 'argd', content = 'dstab', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'dslash', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'dcrush', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'dmagic', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'drange', colspan = '2', class = 'infobox-nested' }
	}
	:pad(10)
	:addRow{
		{ tag = 'th', content = '[[File:Melee.png|link=Equipment Stats#Other bonuses]] [[Equipment Stats#Other bonuses|Other bonuses]]', colspan = '8', class = 'infobox-subheader' },
		{ tag = 'th', content = 'Slot', colspan = '2', class = 'infobox-subheader' }
	}
	:pad(10)
	:addRow{
		{ tag = 'th', content = '[[File:Strength icon.png|link=Strength bonus]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:Ranged Strength icon.png|link=Ranged Strength]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:Magic Damage icon.png|link=Magic damage]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'th', content = '[[File:Prayer icon.png|link=Prayer]]', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argh', content = 'slot_image', colspan = '2', class = 'infobox-nested' }
	}
	ret:addRow{
		{ tag = 'argd', content = 'str', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'rstr', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'mdmg', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'prayer', colspan = '2', class = 'infobox-nested' },
		{ tag = 'argd', content = 'slot_link', colspan = '2', class = 'infobox-nested' }
	}
	:pad(10)

	if any_is_weapon then
		ret:addRow{
			{ tag = 'th', content = '[[Attack speed#Weapon attack speeds|Attack speed]]', colspan = '7', class = 'infobox-subheader' },
			{ tag = 'th', content = '[[Attack range|Range]]', colspan = '3', class = 'infobox-subheader' }
		}
		:pad(10)
		:addRow{
			{ tag = 'argd', content = 'speed', colspan = '7', class = 'infobox-nested' },
			{ tag = 'argd', content = 'attackrange', colspan = '3', class = 'infobox-nested' }
		}
		:pad(10)
	end

	if onmain() then
		local a1 = ret:param('all')
		local a2 = ret:categoryData()
		ret:wikitext(addcategories(a1, a2))
	end
	return ret:tostring()
end

function numericarg_smw(arg)
	if not infobox.isDefined(arg) then
		return nil
	elseif tonumber(arg) ~= nil then
		return arg
	end
	return nil
end

function numericarg(arg, arg_name)
	if not infobox.isDefined(arg) then
		return nil
	end
	return arg
end

-- If the arg is numeric, return the signed version (starts with + or -)
function signednumericarg(arg, arg_name)
	local _arg = numericarg(arg, arg_name)
	if tonumber(_arg) ~= nil then
		return signed(_arg)
	end
	return nil
end

-- Sign the arg and append a percent sign
function signedpercentnumericarg(arg, arg_name)
	local _arg = signednumericarg(arg, arg_name)
	if _arg ~= nil then
		return _arg..'%'
	end
	return nil
end

-- Return attack speed for smw, this should either be a positive integer, 
-- or in the case of a special value a negative number like:
-- -1 for 'No' or 'N/A' values
-- -2 for 'Random' and 'Varies' values.
function speedargsmw(arg)
	if not infobox.isDefined(arg) then
		return nil
	end

    local numarg = tonumber(arg)
    local lowarg = string.lower(arg)

    if numarg ~= nil then
        return numarg
    elseif lowarg == 'n/a' or lowarg == 'no' then
        return -1
    elseif lowarg == 'random' or lowarg == 'varies' then
        return -2
    end

    return nil
end

-- Return the appropriate slot image
function slotarg(arg)
	if not infobox.isDefined(arg) then
		return nil
	end
	local _arg = string.lower(arg)
	if slots[_arg] ~= nil then
		return string.format('[[File:%s slot.png|link=%s slot]]', _arg, _arg)
	end

	return badarg('slot', 'should be a valid slot name.')
end

function slot_link_arg(arg)
	if not infobox.isDefined(arg) then
		return nil
	end
	return '[['..arg..' slot|List]]'
end

-- Returns formatted attack range
function attackrangearg(arg)
	if not infobox.isDefined(arg) then
		return nil
	end

    local lowarg = string.lower(arg)
    if lowarg == 'staff' then
    	return '<span '..
			'title="This attack range refers to the staff\'s melee attack range. All combat spells have an attack range of 10." '..
			'style="cursor:help; border-bottom:1px dotted;">'..
			'1<br/>square</span>'	
	end

    local numarg = tonumber(arg)
	if numarg ~= nil then
		return string.format('%s<br/>%s', arg, (numarg > 1) and 'squares' or 'square')
	elseif lowarg == 'no' or lowarg == 'n/a' then
		return 'N/A'
	end

	return nil
end

-- Return attack range for smw, this should either be a positive integer,
-- or in the case of a special value a negative number like:
-- -1 for 'No' or 'N/A' values
function attackrangeargsmw(arg)
	if not infobox.isDefined(arg) then
		return nil
	end

	local lowarg = string.lower(arg)
	if lowarg == 'staff' then
		return 1
	end
	
    local numarg = tonumber(arg)
	if numarg ~= nil then
		return numarg
	elseif lowarg == 'no' or lowarg == 'n/a' then
		return -1
	end
	
	return nil
end

function imagearg(image, caption, argname)
	if not infobox.isDefined(image) then
		return nil
	end
	if string.lower(image) == 'no' then
		return 'N/A'
	end
	local clean_result = clean({file=image, maxW = 300, maxH = 350})
	if clean_result == nil then
		return badarg(argname, 'should be a valid file.')
	end
	local image_string, width, height = unpack(clean_result)
	local caption_string = ''
	if infobox.isDefined(caption) and string.lower(caption) ~= 'no' then
		caption_string = '<br /><span class="infobox-bonuses-image-caption">' .. caption .. '</span>'
	end
	return image_string..caption_string
end

function image_width_arg(image, argname)
	if not infobox.isDefined(image) then
		return nil
	end
	local clean_result = clean({file=image, maxW = 300, maxH = 350})
	if clean_result == nil then
		return badarg(argname, 'should be a valid file.')
	end
	local image_string, width, height = unpack(clean_result)
	return width
end

-- Get the max width from all versions.
-- Minimum 115, so there's room for the male/female buttons
function max_width(all_widths)
	local res = tonumber(all_widths.d) or 115
	for i, width in ipairs(all_widths.switches or {115}) do
		res = math.max(res, tonumber(width) or 115)
	end
	return math.max(res, 115)
end

-- red ERR span with title hover for explanation
function badarg(argname, argmessage)
	return '<span '..
			'title="The parameter «'..argname..'» '..argmessage..'" '..
			'style="color:red; font-weight:bold; cursor:help; border-bottom:1px dotted red;">'..
			'ERR</span>[[Category:Pages with script errors]]'
end

function addcategories(args, catargs)
	local ret = {}

	if args['slot'] then
		local slot_d = args['slot'].d
		if slots[slot_d] then
			table.insert(ret, slots[slot_d])
		end
		if args['slot'].switches then
			for _, slot_i in ipairs(args['slot'].switches) do
				if slots[slot_i] then
					table.insert(ret, slots[slot_i])
				end
			end
		end
	end

	-- combine table and format category wikicode
	for i, v in ipairs(ret) do
		if (v ~= '') then
			ret[i] = string.format('[[Category:%s]]', v)
		end
	end

	return table.concat(ret, '')
end

--[=[ DEBUG COPYPASTA
= p._main({astab = 7, aslash = 45, acrush = -2, amagic = 0, arange = 0, dstab = 0, dslash = 1, dcrush = 0, dmagic = 0, drange = 0, str = 44, rstr = 0, mdmg = 0, prayer = 0, slot = 'weapon', speed = 4, attackrange = 1, combatstyle = 'hacksword', image = '[[File:Rune scimitar equipped.png|100px]]', caption = 'A total chad wielding a ROOONE SKIMMAY.'})
--]=]

return p