Module:Skills/Summoning: Difference between revisions

From Melvor Idle
No edit summary
(Apply CSS classes to prevent image columns from collapsing on devices with small widths)
(8 intermediate revisions by one other user not shown)
Line 10: Line 10:
local Items = require('Module:Items')
local Items = require('Module:Items')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
local Shop = require('Module:Shop')
local Num = require('Module:Number')
local Num = require('Module:Number')


Line 22: Line 23:


local html = mw.html.create('table')
local html = mw.html.create('table')
:addClass('wikitable sortable stickyHeader')
:addClass('wikitable sortable stickyHeader col-1-img col-5-img')
html:tag('tr'):addClass('headerRow-0')
html:tag('tr'):addClass('headerRow-0')
Line 54: Line 55:
:css('text-align', 'center')
:css('text-align', 'center')
row:tag('td'):wikitext(Icons.getDLCColumnIcon(Fam.id))
row:tag('td'):wikitext(Icons.getDLCColumnIcon(Fam.id))
:css('text-align', 'center')
:attr('data-sort-value', Icons.getExpansionID(Fam.id))
:attr('data-sort-value', Icons.getExpansionID(Fam.id))


Line 72: Line 72:
local args = frame.args ~= nil and frame.args or frame
local args = frame.args ~= nil and frame.args or frame
local realmName = args.realm
local realmName = args.realm
local category = args.category
local realm = Skills.getRealmFromName(realmName)
local realm = Skills.getRealmFromName(realmName)
if realm == nil then
if realm == nil then
Line 77: Line 78:
end
end
local skillID = 'Summoning'
local skillID = 'Summoning'
local html = mw.html.create('table')
:addClass('wikitable sortable stickyHeader col-1-img col-3-img')
local header = html:tag('tr'):addClass('headerRow-0')
header:tag('th'):wikitext('Name')
            :attr('colspan', 2)
header:tag('th'):wikitext('DLC')
header:tag('th'):wikitext(Icons._SkillRealmIcon(skillID, realm.id) .. '<br>Level')
header:tag('th'):wikitext('Tier')
header:tag('th'):wikitext('Creation<br>XP')
header:tag('th'):wikitext('Shards')
header:tag('th'):wikitext('Cost of shards')
if category == 'Combat' then
header:tag('th'):wikitext(Icons.Icon({'Melee', notext=true, nolink=true}) .. '<br>Max Hit')
end
local function getShardCosts(familiar)
local shardCosts = {}
for _, shard in ipairs(familiar.itemCosts) do
local shopItem = Shop.getPurchaseByID(shard.id)
for _, shardCost in ipairs(shopItem.cost.currencies) do
local addCost = shardCost.cost * shard.quantity
if shardCosts[shardCost.currency] ~= nil then
shardCosts[shardCost.currency] = shardCosts[shardCost.currency] + addCost
else
shardCosts[shardCost.currency] = addCost
end
end
end
    return shardCosts
end


local result = ''
local function isCombatFamiliar(fam)
result = result..'{| class="wikitable sortable stickyHeader"'
local item = Items.getItemByID(fam.productID)
result = result..'\r\n|- class="headerRow-0"'
local maxHit = Items._getItemStat(item, 'summoningMaxhit')
result = result..'\r\n!colspan="2"|Name!!Requirements'
return maxHit ~= nil
result = result..'!!Tier!!Effect!!' .. Icons.Icon({'Melee', notext=true, nolink=true}) .. ' Max Hit!!Shard Cost!!Secondary!!Creation XP'
end


local Familiars = GameData.getEntities(SkillData.Summoning.recipes,
local Familiars = GameData.getEntities(SkillData.Summoning.recipes,
function(recipe)
function(recipe)
return Skills.getRecipeRealm(recipe) == realm.id
    return Skills.getRecipeRealm(recipe) == realm.id and
          ((category == 'Combat' and isCombatFamiliar(recipe)) or
          (category ~= 'Combat' and not isCombatFamiliar(recipe)))
end
end
)
)
Line 98: Line 134:
local item = Items.getItemByID(Fam.productID)
local item = Items.getItemByID(Fam.productID)
if item ~= nil then
if item ~= nil then
local maxHit, maxHitText = Items._getItemStat(item, 'summoningMaxhit'), ''
local effectDesc = Modifiers.getModifiersText(item.modifiers, false, false, 10)
if maxHit == nil then
maxHitText = 'class="table-na" data-sort-value="-1"| N/A'
local row = html:tag('tr')
else
row:tag('td'):wikitext(Icons.Icon({item.name, type='item', notext=true}))
maxHit = maxHit * 10
:attr('data-sort-value', item.name)
maxHitText = 'style="text-align:right;" data-sort-value="' .. maxHit .. '"|' .. Num.formatnum(maxHit)
row:tag('td'):wikitext('[[' .. item.name .. ']]')
row:tag('td'):wikitext(Icons.getDLCColumnIcon(Fam.id))
:attr('data-sort-value', Icons.getExpansionID(Fam.id))
row:tag('td'):wikitext(level)
:css('text-align', 'center')
row:tag('td'):wikitext(Fam.tier)
:css('text-align', 'center')
row:tag('td'):wikitext(Num.formatnum(baseXP))
:css('text-align', 'right')
:attr('data-sort-value', baseXP)
local shardCell = row:tag('td')
local shardCostCell = row:tag('td')
if category == 'Combat' then
local maxHit = Items._getItemStat(item, 'summoningMaxhit') * 10
row:tag('td'):wikitext(Num.formatnum(maxHit))
:css('text-align', 'right')
:attr('data-sort-value', maxHit)
end
end
local effectDesc = Modifiers.getModifiersText(item.modifiers, false, false, 10)
local rowText = '|-'
rowText = rowText..'\r\n|data-sort-value="'..item.name..'"|'..Icons.Icon({item.name, type='item', notext=true})
rowText = rowText..'||' .. Icons.getExpansionIcon(Fam.id) .. Icons.Icon({item.name, type='item', noicon=true})
rowText = rowText..'||style="text-align:right" data-sort-value="' .. level .. '"|' .. reqText
rowText = rowText..'||style="text-align:right"|'..Fam.tier
rowText = rowText..'||'..effectDesc..'||'..maxHitText


-- Create item requirements text
-- Shards required
local ShardCostArray, OtherCostArray = {}, {}
for _, cost in ipairs(Fam.itemCosts) do
-- Shards
for j, cost in ipairs(Fam.itemCosts) do
local shard = Items.getItemByID(cost.id)
local shard = Items.getItemByID(cost.id)
if shard ~= nil then
if shard ~= nil then
table.insert(ShardCostArray, Icons.Icon({shard.name, type='item', notext=true, qty=cost.quantity}))
local sub = mw.html.create('sub')
:wikitext(cost.quantity .. 'x'):addClass('item-qty'):done()
shardCell:node(sub)
shardCell:wikitext(Icons.Icon({shard.name, type='item', notext=true}))
end
end
end
end
rowText = rowText..'||style="text-align:right"|'..table.concat(ShardCostArray, ', ')..'&nbsp;'
 
local costTbl = {}
-- Other costs
for costType, cost in pairs(getShardCosts(Fam)) do
local recipeCost = 0
table.insert(costTbl, Icons._Currency(costType, cost))
if isAbyssal == true then
recipeCost = SkillData.Summoning.recipeAPCost
else
recipeCost = SkillData.Summoning.recipeGPCost
end
end
local currencyCostText = Common.getCostString({ ["items"] = {}, ["currencies"] = Fam.currencyCosts})
shardCostCell:wikitext(table.concat(costTbl, '<br>'))
if currencyCostText ~= nil then
:css('text-align', 'right')
table.insert(OtherCostArray, currencyCostText)
end
for j, nonShardID in ipairs(Fam.nonShardItemCosts) do
local nonShard = Items.getItemByID(nonShardID)
if nonShard ~= nil then
local itemValue = math.max(nonShard.sellsFor, 20)
local nonShardQty = math.max(1, math.ceil(recipeCost / itemValue))
table.insert(OtherCostArray, Icons.Icon({nonShard.name, type='item', notext=true, qty=nonShardQty}))
end
end
rowText = rowText..'||style="text-align:right"|'..table.concat(OtherCostArray, "<br/>'''OR''' ")
rowText = rowText..'||style="text-align:right" data-sort-value="' .. baseXP .. '"|' .. Num.formatnum(baseXP)
table.insert(rowArray, rowText)
end
end
end
end


result = result..'\r\n'..table.concat(rowArray, '\r\n')
return tostring(html)
 
result = result..'\r\n|}'
return result
end
end


Line 158: Line 185:
local skillID = 'Summoning'
local skillID = 'Summoning'
local result = ''
local result = ''
result = result..'{| class="wikitable sortable stickyHeader"'
result = result..'{| class="wikitable sortable stickyHeader col-1-img col-3-img"'
result = result..'\r\n|- class="headerRow-0"'
result = result..'\r\n|- class="headerRow-0"'
result = result..'\r\n!colspan="2"|Familiar 1!!colspan="2"|Familiar 2!!Effect!!Requirements'
result = result..'\r\n!colspan="2"|Familiar 1!!colspan="2"|Familiar 2!!Effect!!Requirements'
Line 310: Line 337:


local html = mw.html.create('table')
local html = mw.html.create('table')
:addClass('wikitable sortable stickyHeader')
:addClass('wikitable sortable stickyHeader col-1-img col-3-img')
html:tag('tr'):addClass('headerRow-0')
html:tag('tr'):addClass('headerRow-0')

Revision as of 21:26, 6 July 2024

Documentation for this module may be created at Module:Skills/Summoning/doc

local p = {}

local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Common = require('Module:Common')
local GameData = require('Module:GameData')
local SkillData = GameData.skillData
local Modifiers = require('Module:Modifiers')
local Skills = require('Module:Skills')
local Items = require('Module:Items')
local Icons = require('Module:Icons')
local Shop = require('Module:Shop')
local Num = require('Module:Number')

function p.getMarkTable(frame)
	local args = frame.args ~= nil and frame.args or frame
	local realmName = args.realm
	local realm = Skills.getRealmFromName(realmName)
	if realm == nil then
		return Shared.printError('Failed to find a realm with name ' .. (realmName or 'nil'))
	end
	local skillID = 'Summoning'

	local html = mw.html.create('table')
		:addClass('wikitable sortable stickyHeader col-1-img col-5-img')
		
	html:tag('tr'):addClass('headerRow-0')
			:tag('th'):wikitext('Mark')
					  :attr('colspan', 2)
			:tag('th'):wikitext('Tier')
			:tag('th'):wikitext(Icons._SkillRealmIcon(skillID, realm.id) .. '<br>Level')
			:tag('th'):wikitext('DLC')
			:tag('th'):wikitext('Discovered in')

	local Familiars = GameData.getEntities(SkillData.Summoning.recipes,
		function(obj)
			return Skills.getRecipeRealm(obj) == realm.id
		end
	)
	table.sort(Familiars, function(a, b) return Skills.standardRecipeSort(skillID, a, b) end)

	local rowArray = {}
	for i, Fam in ipairs(Familiars) do
		local level = Skills.getRecipeLevel(skillID, Fam)
		local reqText = Skills.getRecipeRequirementText(SkillData.Summoning.name, Fam)
		local item = Items.getItemByID(Fam.productID)
		if item ~= nil then
			local row = html:tag('tr')
			row:tag('td'):wikitext(Icons.Icon({item.name, type='mark', notext=true}))
						 :attr('data-sort-value', item.name)
			row:tag('td'):wikitext(Icons.Icon({item.name, 'Mark of the ' .. item.name, type='mark', noicon=true}))
			row:tag('td'):wikitext(Fam.tier)
						 :css('text-align', 'center')
			row:tag('td'):wikitext(level)
						 :css('text-align', 'center')
			row:tag('td'):wikitext(Icons.getDLCColumnIcon(Fam.id))
						 :attr('data-sort-value', Icons.getExpansionID(Fam.id))

			local discoveredArray = {}
			for j, SkillID in ipairs(Fam.skillIDs) do
				table.insert(discoveredArray, Icons.Icon({Constants.getSkillName(SkillID), type='skill'}))
			end
			
			row:tag('td'):wikitext(table.concat(discoveredArray, '<br/>'))
		end
	end
	
	return tostring(html)
end

function p.getTabletTable(frame)
	local args = frame.args ~= nil and frame.args or frame
	local realmName = args.realm
	local category = args.category
	local realm = Skills.getRealmFromName(realmName)
	if realm == nil then
		return Shared.printError('Failed to find a realm with name ' .. (realmName or 'nil'))
	end
	local skillID = 'Summoning'
	
	local html = mw.html.create('table')
		:addClass('wikitable sortable stickyHeader col-1-img col-3-img')
	
	local header = html:tag('tr'):addClass('headerRow-0')
	header:tag('th'):wikitext('Name')
		            :attr('colspan', 2)
	header:tag('th'):wikitext('DLC')
	header:tag('th'):wikitext(Icons._SkillRealmIcon(skillID, realm.id) .. '<br>Level')
	header:tag('th'):wikitext('Tier')
	header:tag('th'):wikitext('Creation<br>XP')
	header:tag('th'):wikitext('Shards')
	header:tag('th'):wikitext('Cost of shards')
	
	if category == 'Combat' then
		header:tag('th'):wikitext(Icons.Icon({'Melee', notext=true, nolink=true}) .. '<br>Max Hit')
	end
	
	local function getShardCosts(familiar)
		local shardCosts = {}
		for _, shard in ipairs(familiar.itemCosts) do
			local shopItem = Shop.getPurchaseByID(shard.id)
			for _, shardCost in ipairs(shopItem.cost.currencies) do
				local addCost = shardCost.cost * shard.quantity
				if shardCosts[shardCost.currency] ~= nil then
					shardCosts[shardCost.currency] = shardCosts[shardCost.currency] + addCost
				else
					shardCosts[shardCost.currency] = addCost
				end
			end
		end
    	return shardCosts
	end

	local function isCombatFamiliar(fam)
		local item = Items.getItemByID(fam.productID)
		local maxHit = Items._getItemStat(item, 'summoningMaxhit')
		return maxHit ~= nil
	end

	local Familiars = GameData.getEntities(SkillData.Summoning.recipes,
		function(recipe)
    		return Skills.getRecipeRealm(recipe) == realm.id and 
           ((category == 'Combat' and isCombatFamiliar(recipe)) or
           (category ~= 'Combat' and not isCombatFamiliar(recipe)))
		end
	)
	table.sort(Familiars, function(a, b) return Skills.standardRecipeSort(skillID, a, b) end)

	local rowArray = {}
	for i, Fam in ipairs(Familiars) do
		local level, isAbyssal = Skills.getRecipeLevelRealm(skillID, Fam)
		local baseXP = Fam.baseAbyssalExperience or Fam.baseExperience
		local reqText = Skills.getRecipeRequirementText(SkillData.Summoning.name, Fam)
		local item = Items.getItemByID(Fam.productID)
		if item ~= nil then
			local effectDesc = Modifiers.getModifiersText(item.modifiers, false, false, 10)
			
			local row = html:tag('tr')
			row:tag('td'):wikitext(Icons.Icon({item.name, type='item', notext=true}))
						 :attr('data-sort-value', item.name)
			row:tag('td'):wikitext('[[' .. item.name .. ']]')
			row:tag('td'):wikitext(Icons.getDLCColumnIcon(Fam.id))
						 :attr('data-sort-value', Icons.getExpansionID(Fam.id))
			row:tag('td'):wikitext(level)
						 :css('text-align', 'center')
			row:tag('td'):wikitext(Fam.tier)
						 :css('text-align', 'center')
			row:tag('td'):wikitext(Num.formatnum(baseXP))
						 :css('text-align', 'right')
						 :attr('data-sort-value', baseXP)
			local shardCell = row:tag('td')
			local shardCostCell = row:tag('td')
			
			if category == 'Combat' then
				local maxHit = Items._getItemStat(item, 'summoningMaxhit') * 10
				row:tag('td'):wikitext(Num.formatnum(maxHit))
							 :css('text-align', 'right')
							 :attr('data-sort-value', maxHit)
			end

			-- Shards required
			for _, cost in ipairs(Fam.itemCosts) do
				local shard = Items.getItemByID(cost.id)
				if shard ~= nil then
					local sub = mw.html.create('sub')
						:wikitext(cost.quantity .. 'x'):addClass('item-qty'):done()
					shardCell:node(sub)
					shardCell:wikitext(Icons.Icon({shard.name, type='item', notext=true}))
				end
			end
			
			local costTbl = {}
			for costType, cost in pairs(getShardCosts(Fam)) do
				table.insert(costTbl, Icons._Currency(costType, cost))
			end
			shardCostCell:wikitext(table.concat(costTbl, '<br>'))
						 :css('text-align', 'right')
		end
	end

	return tostring(html)
end

function p._getSynergyTable(familiarIDs)
	local skillID = 'Summoning'
	local result = ''
	result = result..'{| class="wikitable sortable stickyHeader col-1-img col-3-img"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!colspan="2"|Familiar 1!!colspan="2"|Familiar 2!!Effect!!Requirements'

	local recipesByID, famNames = {}, {}
	for i, recipe in ipairs(SkillData.Summoning.recipes) do
		recipesByID[recipe.id] = recipe
		local item = Items.getItemByID(recipe.productID)
		if item ~= nil then
			famNames[recipe.id] = item.name
		end
	end

	local synergyList = GameData.getEntities(SkillData.Summoning.synergies,
		function(synergy)
			for i, summonID in ipairs(synergy.summonIDs) do
				if Shared.contains(familiarIDs, summonID) then
					return true
				end
			end
			return false
		end)
	table.sort(synergyList,
		function (a, b)
			local recA1, recB1 = recipesByID[a.summonIDs[1]], recipesByID[b.summonIDs[1]]

			if ((recA1.abyssalLevel or 0) == (recB1.abyssalLevel or 0)) and (recA1.level == recB1.level) then
				return (
					(a.summonIDs[1] == b.summonIDs[1] and a.summonIDs[2] < b.summonIDs[2])
					or a.summonIDs[1] < b.summonIDs[1]
				 )
			else
				return Skills.standardRecipeSort(skillID, recA1, recB1)
			end
		end
	)

	local rowArray = {}
	for i, syn in ipairs(synergyList) do
		local Fam1 = recipesByID[syn.summonIDs[1]]
		local Fam2 = recipesByID[syn.summonIDs[2]]
		if Fam1 ~= nil and Fam2 ~= nil then
			local FamName1 = famNames[Fam1.id] or 'Unknown'
			local FamName2 = famNames[Fam2.id] or 'Unknown'
			local synDesc = syn.customDescription
			if synDesc == nil then
				-- Generate description from modifiers
				synDesc = Modifiers.getModifiersText(syn.modifiers, false, false, 10) or ''
			end
			local rowText = '|-'
			rowText = rowText..'\r\n|data-sort-value="'..FamName1..'"|'..Icons.Icon({FamName1, type='item', notext=true})
			rowText = rowText..'||' .. Icons.getExpansionIcon(Fam1.id) .. Icons.Icon({FamName1, type='item', noicon=true})
			rowText = rowText..'||data-sort-value="'..FamName2..'"|'..Icons.Icon({FamName2, type='item', notext=true})
			rowText = rowText..'||' .. Icons.getExpansionIcon(Fam2.id) .. Icons.Icon({FamName2, type='item', noicon=true})
			rowText = rowText..'||'..synDesc

			local reqArray = {}
			local reqFam = (Skills.getRecipeLevel(skillID, Fam1) > Skills.getRecipeLevel(skillID, Fam2) and Fam1) or Fam2
			local reqLvl = Skills.getRecipeLevel(skillID, reqFam)
			table.insert(reqArray, Skills.getRecipeRequirementText(skillID, reqFam))
			table.insert(reqArray, FamName1..' Mark Level '..(Fam2.tier + 1))
			table.insert(reqArray, FamName2..' Mark Level '..(Fam1.tier + 1))

			rowText = rowText..'||data-sort-value="'..reqLvl..'"|'..table.concat(reqArray, '<br/>')

			table.insert(rowArray, rowText)
		end
	end

	result = result..'\r\n'..table.concat(rowArray, '\r\n')

	result = result..'\r\n|}'
	return result
end

function p.getSynergyTable(frame)
	local args = frame.args ~= nil and frame.args or frame
	local realmName = args.realm
	local realm = Skills.getRealmFromName(realmName)
	if realm == nil then
		return Shared.printError('Failed to find a realm with name ' .. (realmName or 'nil'))
	end

	local familiarIDs = {}
	for i, recipe in ipairs(SkillData.Summoning.recipes) do
		if Skills.getRecipeRealm(recipe) == realm.id then
			table.insert(familiarIDs, recipe.id)
		end
	end

	return p._getSynergyTable(familiarIDs)
end

function p.getFamiliarSynergyTable(frame)
	local famName = frame.args ~= nil and frame.args[1] or frame
	local familiarID = nil
	local familiarItem = Items.getItem(famName)
	if familiarItem == nil then
		return Shared.printError('Not a valid familiar')
	else
		for i, recipe in ipairs(SkillData.Summoning.recipes) do
			if recipe.productID == familiarItem.id then
				familiarID = recipe.id
				break
			end
		end
		if familiarID == nil then
			return Shared.printError('Not a valid familiar')
		else
			return p._getSynergyTable({ familiarID })
		end
	end
end

function p._getSkillSummoningBonusTable(skill)
	local rowArray = {}
	local famNames = {}

	-- Familiars
	for i, recipe in ipairs(SkillData.Summoning.recipes) do
		local item = Items.getItemByID(recipe.productID)
		if item ~= nil then
			famNames[recipe.id] = item.name
			if item.modifiers ~= nil and not Shared.tableIsEmpty(item.modifiers) then
				local famSkills = Modifiers.getModifierSkills(item.modifiers)
				if Shared.contains(famSkills, skill) then
					table.insert(rowArray, {Fam1 = item.name, FamID1 = item.id, Fam2 = nil, FamID2 = nil, Descrip = Modifiers.getModifiersText(item.modifiers, false)})
				end
			end
		end
	end

	-- Synergies
	for i, syn in ipairs(SkillData.Summoning.synergies) do
		local synSkills = Modifiers.getModifierSkills(syn.modifiers)
		if Shared.contains(synSkills, skill) then
			local FamName1 = famNames[syn.summonIDs[1]] or 'Unknown'
			local FamName2 = famNames[syn.summonIDs[2]] or 'Unknown'
			local synDesc = syn.customDescription
			if synDesc == nil then
				-- Generate description from modifiers
				synDesc = Modifiers.getModifiersText(syn.modifiers, false) or ''
			end
			table.insert(rowArray, {Fam1 = FamName1, FamID1 = syn.summonIDs[1], Fam2 = FamName2, FamID2 = syn.summonIDs[2], Descrip = synDesc})
		end
	end

	if Shared.tableIsEmpty(rowArray) then
		return ''
	end

	local html = mw.html.create('table')
		:addClass('wikitable sortable stickyHeader col-1-img col-3-img')
		
	html:tag('tr'):addClass('headerRow-0')
			:tag('th'):wikitext('Familiar 1')
					  :attr('colspan', 2)
			:tag('th'):wikitext('Familiar 2')
					  :attr('colspan', 2)
			:tag('th'):wikitext('DLC')
			:tag('th'):wikitext('Effect')
	
	

	for i, rowItem in ipairs(rowArray) do
		local DLCIcon = Icons.getExpansionIcon(rowItem.FamID1)
		local row = html:tag('tr')
		row:tag('td'):wikitext(Icons.Icon({rowItem.Fam1, type='item', notext=true}))
					 :attr('data-sort-value', rowItem.Fam1)
		row:tag('td'):wikitext(Icons.Icon({rowItem.Fam1, type='item', noicon=true}))
		
		if rowItem.Fam2 ~= nil then
			-- If Fam1 has no DLC, try setting it for Fam2
			if DLCIcon == nil or DLCIcon == '' then
				DLCIcon = Icons.getExpansionIcon(rowItem.FamID2)
			end
			row:tag('td'):wikitext(Icons.Icon({rowItem.Fam2, type='item', notext=true}))
						 :attr('data-sort-value', rowItem.Fam2)
			row:tag('td'):wikitext(Icons.Icon({rowItem.Fam2, type='item', noicon=true}))
		else
			row:tag('td'):tag('td')
		end

		-- If both familiars have no DLC, default to melvor icon.
		if DLCIcon == nil or DLCIcon == '' then
			DLCIcon = Icons.Melvor()
		end
		-- As of 06/07/2024, no synergies exist that use two DLCs
		row:tag('td'):wikitext(DLCIcon)
					 :css('text-align', 'center')

		row:tag('td'):wikitext(rowItem.Descrip or ' ')
	end
	
	return tostring(html)

end

function p.getSkillSummoningBonusTable(frame)
	local skillName = frame.args ~= nil and frame.args[1] or frame
	return p._getSkillSummoningBonusTable(skillName)
end

return p