<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.runerealm.org/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FUser%3AJakesterwars%2FSkill_calc</id>
	<title>Module:Sandbox/User:Jakesterwars/Skill calc - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.runerealm.org/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FUser%3AJakesterwars%2FSkill_calc"/>
	<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=Module:Sandbox/User:Jakesterwars/Skill_calc&amp;action=history"/>
	<updated>2026-04-30T12:53:47Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://wiki.runerealm.org/index.php?title=Module:Sandbox/User:Jakesterwars/Skill_calc&amp;diff=35120&amp;oldid=prev</id>
		<title>Alex: Created page with &quot;local p = {}  local helpers = require(string.format(&#039;%s/Helpers&#039;, mw.getCurrentFrame():getTitle())) local commas = require(&#039;Module:Addcommas&#039;)._add local coins = require(&#039;Module:Coins&#039;)._amount local gePrices = mw.loadJsonData(&#039;Module:GEPrices/data.json&#039;)  local farmingCTS = { 	[&#039;Potato&#039;] = { 101, 180 }, 	[&#039;Onion&#039;] = { 105, 180 }, 	[&#039;Cabbage&#039;] = { 107, 180 }, 	[&#039;Tomato&#039;] = { 112, 180 }, 	[&#039;Sweetcorn&#039;] = { 88, 180 }, 	[&#039;Strawberry&#039;] = { 103, 180 }, 	[&#039;Watermelon&#039;] = { 126...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=Module:Sandbox/User:Jakesterwars/Skill_calc&amp;diff=35120&amp;oldid=prev"/>
		<updated>2024-10-16T23:13:03Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;local p = {}  local helpers = require(string.format(&amp;#039;%s/Helpers&amp;#039;, mw.getCurrentFrame():getTitle())) local commas = require(&amp;#039;Module:Addcommas&amp;#039;)._add local coins = require(&amp;#039;Module:Coins&amp;#039;)._amount local gePrices = mw.loadJsonData(&amp;#039;Module:GEPrices/data.json&amp;#039;)  local farmingCTS = { 	[&amp;#039;Potato&amp;#039;] = { 101, 180 }, 	[&amp;#039;Onion&amp;#039;] = { 105, 180 }, 	[&amp;#039;Cabbage&amp;#039;] = { 107, 180 }, 	[&amp;#039;Tomato&amp;#039;] = { 112, 180 }, 	[&amp;#039;Sweetcorn&amp;#039;] = { 88, 180 }, 	[&amp;#039;Strawberry&amp;#039;] = { 103, 180 }, 	[&amp;#039;Watermelon&amp;#039;] = { 126...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local p = {}&lt;br /&gt;
&lt;br /&gt;
local helpers = require(string.format(&amp;#039;%s/Helpers&amp;#039;, mw.getCurrentFrame():getTitle()))&lt;br /&gt;
local commas = require(&amp;#039;Module:Addcommas&amp;#039;)._add&lt;br /&gt;
local coins = require(&amp;#039;Module:Coins&amp;#039;)._amount&lt;br /&gt;
local gePrices = mw.loadJsonData(&amp;#039;Module:GEPrices/data.json&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
local farmingCTS = {&lt;br /&gt;
	[&amp;#039;Potato&amp;#039;] = { 101, 180 },&lt;br /&gt;
	[&amp;#039;Onion&amp;#039;] = { 105, 180 },&lt;br /&gt;
	[&amp;#039;Cabbage&amp;#039;] = { 107, 180 },&lt;br /&gt;
	[&amp;#039;Tomato&amp;#039;] = { 112, 180 },&lt;br /&gt;
	[&amp;#039;Sweetcorn&amp;#039;] = { 88, 180 },&lt;br /&gt;
	[&amp;#039;Strawberry&amp;#039;] = { 103, 180 },&lt;br /&gt;
	[&amp;#039;Watermelon&amp;#039;] = { 126, 180 },&lt;br /&gt;
	[&amp;#039;Snape grass&amp;#039;] = { 148, 195 },&lt;br /&gt;
	[&amp;#039;Hammerstone hops&amp;#039;] = { 104, 180 },&lt;br /&gt;
	[&amp;#039;Asgarnian hops&amp;#039;] = { 108, 180 },&lt;br /&gt;
	[&amp;#039;Yanillian hops&amp;#039;] = { 116, 180 },&lt;br /&gt;
	[&amp;#039;Krandorian hops&amp;#039;] = { 120, 180 },&lt;br /&gt;
	[&amp;#039;Wildblood hops&amp;#039;] = { 128, 180 },&lt;br /&gt;
	[&amp;#039;Barley&amp;#039;] = { 103, 180 },&lt;br /&gt;
	[&amp;#039;Jute fibre&amp;#039;] = { 113, 180 },&lt;br /&gt;
	[&amp;#039;Giant seaweed&amp;#039;] = { 150, 210 },&lt;br /&gt;
	[&amp;#039;Guam leaf&amp;#039;] = { 25, 80 },&lt;br /&gt;
	[&amp;#039;Marrentill&amp;#039;] = { 28, 80 },&lt;br /&gt;
	[&amp;#039;Tarromin&amp;#039;] = { 31, 80 },&lt;br /&gt;
	[&amp;#039;Harralander&amp;#039;] = { 36, 80 },&lt;br /&gt;
	[&amp;#039;Goutweed&amp;#039;] = { 39, 80 },&lt;br /&gt;
	[&amp;#039;Ranarr weed&amp;#039;] = { 39, 80 },&lt;br /&gt;
	[&amp;#039;Toadflax&amp;#039;] = { 43, 80 },&lt;br /&gt;
	[&amp;#039;Irit leaf&amp;#039;] = { 46, 80 },&lt;br /&gt;
	[&amp;#039;Avantoe&amp;#039;] = { 50, 80 },&lt;br /&gt;
	[&amp;#039;Kwuarm&amp;#039;] = { 54, 80 },&lt;br /&gt;
	[&amp;#039;Snapdragon&amp;#039;] = { 56, 80 },&lt;br /&gt;
	[&amp;#039;Cadantine&amp;#039;] = { 59, 80 },&lt;br /&gt;
	[&amp;#039;Lantadyme&amp;#039;] = { 64, 80 },&lt;br /&gt;
	[&amp;#039;Dwarf weed&amp;#039;] = { 67, 80 },&lt;br /&gt;
	[&amp;#039;Torstol&amp;#039;] = { 71, 80 }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local itemBonuses = {&lt;br /&gt;
	[&amp;#039;secateurs&amp;#039;] = 0.10,&lt;br /&gt;
	[&amp;#039;farmingCape&amp;#039;] = 0.05&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local otherBonuses = {&lt;br /&gt;
	[&amp;#039;attas&amp;#039;] = 0.05,&lt;br /&gt;
	[&amp;#039;diary&amp;#039;] = {&lt;br /&gt;
		[&amp;#039;None&amp;#039;] = 0,&lt;br /&gt;
		[&amp;#039;Hard Kourend&amp;#039;] = 0.05,&lt;br /&gt;
		[&amp;#039;Medium Kandarin&amp;#039;] = 0.05,&lt;br /&gt;
		[&amp;#039;Hard Kandarin&amp;#039;] = 0.1,&lt;br /&gt;
		[&amp;#039;Elite Kandarin&amp;#039;] = 0.15&lt;br /&gt;
	},&lt;br /&gt;
	[&amp;#039;Ectofuntus&amp;#039;] = 4,&lt;br /&gt;
	[&amp;#039;Gilded&amp;#039;] = 3.5,&lt;br /&gt;
	[&amp;#039;Chaos altar&amp;#039;] = 7,&lt;br /&gt;
	[&amp;#039;Limestone altar&amp;#039;] = 2.75,&lt;br /&gt;
	[&amp;#039;Sacred bone burner&amp;#039;] = 3&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local compostValues = {&lt;br /&gt;
	[&amp;#039;None&amp;#039;] = { 0, 0 },&lt;br /&gt;
	[&amp;#039;Compost&amp;#039;] = { 1, 18 },&lt;br /&gt;
	[&amp;#039;Supercompost&amp;#039;] = { 2, 26 },&lt;br /&gt;
	[&amp;#039;Ultracompost&amp;#039;] = { 3, 36 }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local serviceFeeValues = {&lt;br /&gt;
	[&amp;#039;None&amp;#039;] = 0,&lt;br /&gt;
	[&amp;#039;Phials&amp;#039;] = 5,&lt;br /&gt;
	[&amp;#039;Virilis&amp;#039;] = 10,&lt;br /&gt;
	[&amp;#039;Elder Chaos druid&amp;#039;] = 50&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	&lt;br /&gt;
	-- Compute current/goal levels and experience as well as the experience remaining between the difference&lt;br /&gt;
	local bulkLevelInformation = helpers.calculateCurrentGoalInformation(args.current, args.currentToggle, args.goal, args.goalToggle)&lt;br /&gt;
	&lt;br /&gt;
	-- Pull out the relevant data from the sub module and call the function with the passed in skill method&lt;br /&gt;
	local methods = mw.loadData(string.format(&amp;#039;%s/%s&amp;#039;, mw.getCurrentFrame():getTitle(), args.skill))&lt;br /&gt;
	-- Pull and sort the data&lt;br /&gt;
	-- Calculators may or may not have a stepLimit param; only do additional filtering if it&amp;#039;s used&lt;br /&gt;
	local data&lt;br /&gt;
	if args.stepLimit ~= nil then &lt;br /&gt;
		local filteredData = helpers.filterData(methods, args.method, args.dataCriteria, bulkLevelInformation.goalLevel)&lt;br /&gt;
		data = {}&lt;br /&gt;
		for _, v in ipairs(filteredData) do&lt;br /&gt;
			if tostring(args.stepLimit):lower() == &amp;#039;show all&amp;#039; or v.steps == tonumber(args.stepLimit) then&lt;br /&gt;
				table.insert(data, v)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		data = helpers.filterData(methods, args.method, args.dataCriteria, bulkLevelInformation.goalLevel)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local setValue = 0&lt;br /&gt;
	-- Check if the skill the calculator is using is eligible for the experience set bonus&lt;br /&gt;
	if helpers.checkForBoostingSetSkill(args.skill) then&lt;br /&gt;
		local pieces = {&lt;br /&gt;
			{ args.head, 0.004 },&lt;br /&gt;
			{ args.body, 0.008 },&lt;br /&gt;
			{ args.legs, 0.006 },&lt;br /&gt;
			{ args.boots, 0.002 }&lt;br /&gt;
		}&lt;br /&gt;
		local zealotRobes = {&lt;br /&gt;
			{ args.head, 0.0125 },&lt;br /&gt;
			{ args.body, 0.0125 },&lt;br /&gt;
			{ args.legs, 0.0125 },&lt;br /&gt;
			{ args.boots, 0.0125 }&lt;br /&gt;
		}&lt;br /&gt;
		local piecesToSend = args.skill == &amp;#039;Prayer&amp;#039; and zealotRobes or pieces&lt;br /&gt;
		local newSetValue = helpers.determineSetValue(piecesToSend, args.skill)&lt;br /&gt;
		setValue = newSetValue&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Build a message for the user to show the difference between current and goal experience&lt;br /&gt;
	local message = helpers.createMessage(args.skill, bulkLevelInformation)&lt;br /&gt;
&lt;br /&gt;
	local options = {&lt;br /&gt;
		skill = args.skill,&lt;br /&gt;
		experienceRemaining = bulkLevelInformation.experienceRemaining,&lt;br /&gt;
		currentLevel = bulkLevelInformation.currentLevel,&lt;br /&gt;
		setValue = setValue,&lt;br /&gt;
		secateurs = args.secateurs,&lt;br /&gt;
		farmingCape = args.farmingCape,&lt;br /&gt;
		diary = args.diary,&lt;br /&gt;
		attas = args.attas,&lt;br /&gt;
		compost = args.compost,&lt;br /&gt;
		unnotingService = args.unnotingService,&lt;br /&gt;
		bonus = args.bonus,&lt;br /&gt;
		dataCriteria = args.dataCriteria,&lt;br /&gt;
		leagueMultiplier = args.leagueMultiplier or 1&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	-- Create the headers and alignments&lt;br /&gt;
	local ret = createHeaders(args.skill)&lt;br /&gt;
	&lt;br /&gt;
	-- Loop through the data and make each table row of data (including calculations)&lt;br /&gt;
	for _, v in ipairs(data) do&lt;br /&gt;
		if ({ Woodcutting = true, Mining = true })[args.skill] then&lt;br /&gt;
			ret:node(make_row_no_materials(v, options))&lt;br /&gt;
		elseif ({ Agility = true, Thieving = true })[args.skill] then&lt;br /&gt;
			ret:node(make_row_barebones(v, options))&lt;br /&gt;
		elseif ({ Firemaking = true, Prayer = true, Construction = true })[args.skill] then&lt;br /&gt;
			ret:node(make_row_no_profit(v, options, args.skill))&lt;br /&gt;
		else&lt;br /&gt;
			ret:node(make_row_full(v, options))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Return the table and message to the user&lt;br /&gt;
	return tostring(message) .. tostring(ret)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function spreadMaterials(materials, actionsNeeded, reducedActionsNeeded)&lt;br /&gt;
	local materialsFormatted = &amp;#039;&amp;#039;&lt;br /&gt;
	if materials == nil then&lt;br /&gt;
		return &amp;#039;-&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for _, v in ipairs(materials) do&lt;br /&gt;
		local actionsReduced = (reducedActionsNeeded and tonumber(reducedActionsNeeded) or v.onlyone and 1 or tonumber(actionsNeeded))&lt;br /&gt;
		--quantity is actionsNeeded for farming, not actionsReduced.  test change for herbs&lt;br /&gt;
		local quantity = math.ceil((v.quantity or 1) * (v.onlyone and 1 or tonumber(actionsNeeded)))&lt;br /&gt;
		materialsFormatted = materialsFormatted .. string.format(&amp;#039;%s × [[File:%s.png|link=%s]] [[%s|%s]]&amp;lt;br&amp;gt;&amp;#039;, commas(quantity), v.name, v.name, v.name, v.title or v.name)&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	return string.len(materialsFormatted) &amp;gt; 1 and materialsFormatted or &amp;#039;-&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getInputCost(materials, actionsNeeded, reducedActionsNeeded)&lt;br /&gt;
	local totalCost = 0&lt;br /&gt;
	&lt;br /&gt;
	if materials == nil then&lt;br /&gt;
		return totalCost&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for _, v in ipairs(materials) do&lt;br /&gt;
		local actionsReduced = (reducedActionsNeeded and tonumber(reducedActionsNeeded) or v.onlyone and 1 or tonumber(actionsNeeded))&lt;br /&gt;
		-- adjust quantity based on number of actions needed&lt;br /&gt;
		local quantity = (v.quantity and v.quantity or 1)&lt;br /&gt;
		if v.cost then&lt;br /&gt;
			totalCost = totalCost + (v.cost * (quantity * (v.onlyone and 1 or tonumber(actionsNeeded))))&lt;br /&gt;
		elseif gePrices[v.name] ~= nil then&lt;br /&gt;
			totalCost = totalCost + (gePrices[v.name] * (quantity * (v.onlyone and 1 or tonumber(actionsNeeded))))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return math.ceil(totalCost)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getOutputPrice(name, outputItem, outputQuantity, actionsNeeded, reducedActionsNeeded)&lt;br /&gt;
	local itemToLookUp = outputItem and outputItem or name&lt;br /&gt;
	if gePrices[itemToLookUp] ~= nil then&lt;br /&gt;
		-- Scale quantity based off actions needed for farming.&lt;br /&gt;
		return (gePrices[itemToLookUp] * outputQuantity) * (tonumber(actionsNeeded))&lt;br /&gt;
	else&lt;br /&gt;
		return 0&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function createHeaders(skill)&lt;br /&gt;
	local ret&lt;br /&gt;
	&lt;br /&gt;
	if ({ Woodcutting = true, Mining = true })[skill] then&lt;br /&gt;
		ret = mw.html.create(&amp;#039;table&amp;#039;):addClass(&amp;#039;wikitable sortable sticky-header align-center-1 align-center-3 align-center-4 align-center-5 align-right-6 align-right-7&amp;#039;)&lt;br /&gt;
		ret:tag(&amp;#039;tr&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):attr(&amp;#039;colspan&amp;#039;, 2):wikitext(&amp;#039;Action&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Level&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;XP&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;# Needed&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Output Price&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;GP/XP&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Members&amp;#039;)&lt;br /&gt;
	elseif ({ Agility = true, Thieving = true })[skill] then&lt;br /&gt;
		ret = mw.html.create(&amp;#039;table&amp;#039;):addClass(&amp;#039;wikitable sortable sticky-header align-center-1 align-center-3 align-center-4 align-center-5&amp;#039;)&lt;br /&gt;
		ret:tag(&amp;#039;tr&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):attr(&amp;#039;colspan&amp;#039;, 2):wikitext(&amp;#039;Action&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Level&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;XP&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;# Needed&amp;#039;)&lt;br /&gt;
	elseif ({ Firemaking = true, Prayer = true, Construction = true })[skill] then&lt;br /&gt;
		ret = mw.html.create(&amp;#039;table&amp;#039;):addClass(&amp;#039;wikitable sortable sticky-header align-center-1 align-center-3 align-center-4 align-center-5 align-right-7 align-right-8&amp;#039;)&lt;br /&gt;
		ret:tag(&amp;#039;tr&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):attr(&amp;#039;colspan&amp;#039;, 2):wikitext(&amp;#039;Action&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Level&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;XP&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;# Needed&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Materials&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Input Cost&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;GP/XP&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Members&amp;#039;)&lt;br /&gt;
	else&lt;br /&gt;
		ret = mw.html.create(&amp;#039;table&amp;#039;):addClass(&amp;#039;wikitable sortable sticky-header align-center-1 align-center-3 align-center-4 align-center-5 align-right-7 align-right-8 align-right-9 align-right-10&amp;#039;)&lt;br /&gt;
		ret:tag(&amp;#039;tr&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):attr(&amp;#039;colspan&amp;#039;, 2):wikitext(&amp;#039;Action&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Level&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;XP&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;# Needed&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Materials&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Input Cost&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Output Price&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Profit/Loss&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;GP/XP&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Members&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function make_row_no_materials(action, options)&lt;br /&gt;
	local rowColor = options.dataCriteria == &amp;#039;Greyed out&amp;#039; and helpers.isRowGrey(action.level, options.currentLevel) or &amp;#039;&amp;#039;&lt;br /&gt;
	local picture = action.pic or action.name&lt;br /&gt;
	local actionExperience = (helpers.jagexFloor(action.xp * options.setValue, 1) + action.xp) * options.leagueMultiplier&lt;br /&gt;
	local numberOfActionsNeeded = math.ceil(options.experienceRemaining / actionExperience)&lt;br /&gt;
	local outputQuantity = action.outputQuantity and action.outputQuantity or 1&lt;br /&gt;
	local members = helpers.membersIcon(action.members)&lt;br /&gt;
	local outputPrice = getOutputPrice(action.name, action.outputItem, outputQuantity, numberOfActionsNeeded, reducedNumberOfActions)&lt;br /&gt;
	local gpXp = numberOfActionsNeeded == 0 and 0 or (outputPrice / actionExperience) / numberOfActionsNeeded&lt;br /&gt;
    local namestr = action.title and &amp;#039;[[&amp;#039; .. action.name .. &amp;#039;|&amp;#039; .. action.title .. &amp;#039;]]&amp;#039; or &amp;#039;[[&amp;#039; .. action.name .. &amp;#039;]]&amp;#039;&lt;br /&gt;
    namestr = action.subtxt and string.format(&amp;#039;%s &amp;lt;br /&amp;gt;&amp;lt;small&amp;gt;(%s)&amp;lt;/small&amp;gt;&amp;#039;, namestr, action.subtxt) or namestr&lt;br /&gt;
&lt;br /&gt;
	return mw.html.create(&amp;#039;tr&amp;#039;):addClass(rowColor)&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(&amp;#039;[[File:&amp;#039; .. picture .. &amp;#039;.png|link=&amp;#039; .. action.name .. &amp;#039;]]&amp;#039;):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(namestr):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(action.level or 1):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(commas(actionExperience)):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(commas(numberOfActionsNeeded)):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(coins(commas(outputPrice))):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(coins(commas(gpXp))):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(members):done()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function make_row_barebones(action, options)&lt;br /&gt;
	local actionExperience&lt;br /&gt;
	local rowColor = options.dataCriteria == &amp;#039;Greyed out&amp;#039; and helpers.isRowGrey(action.level, options.currentLevel) or &amp;#039;&amp;#039;&lt;br /&gt;
	local picture = action.pic or action.name&lt;br /&gt;
	if action.name == &amp;#039;Agility Pyramid&amp;#039; then&lt;br /&gt;
		actionExperience = (helpers.jagexFloor(action.xp * options.setValue, 1) + action.xp + (options.currentLevel &amp;lt; 88 and (300 + (options.currentLevel * 8)) or 1000)) * options.leagueMultiplier&lt;br /&gt;
	else&lt;br /&gt;
		actionExperience = (helpers.jagexFloor(action.xp * options.setValue, 1) + action.xp) * options.leagueMultiplier&lt;br /&gt;
	end&lt;br /&gt;
	local numberOfActionsNeeded = math.ceil(options.experienceRemaining / actionExperience)&lt;br /&gt;
    local namestr = action.title and &amp;#039;[[&amp;#039; .. action.name .. &amp;#039;|&amp;#039; .. action.title .. &amp;#039;]]&amp;#039; or &amp;#039;[[&amp;#039; .. action.name .. &amp;#039;]]&amp;#039;&lt;br /&gt;
    namestr = action.subtxt and string.format(&amp;#039;%s &amp;lt;br /&amp;gt;&amp;lt;small&amp;gt;(%s)&amp;lt;/small&amp;gt;&amp;#039;, namestr, action.subtxt) or namestr&lt;br /&gt;
&lt;br /&gt;
	return mw.html.create(&amp;#039;tr&amp;#039;):addClass(rowColor)&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(&amp;#039;[[File:&amp;#039; .. picture .. &amp;#039;.png|link=&amp;#039; .. action.name .. &amp;#039;]]&amp;#039;):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(namestr):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(action.level or 1):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(commas(actionExperience)):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(commas(numberOfActionsNeeded)):done()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function make_row_no_profit(action, options, skill)&lt;br /&gt;
	local actionExperience&lt;br /&gt;
	local rowColor = options.dataCriteria == &amp;#039;Greyed out&amp;#039; and helpers.isRowGrey(action.level, options.currentLevel) or &amp;#039;&amp;#039;&lt;br /&gt;
	local picture = action.pic or action.name&lt;br /&gt;
	local boostablexp = action.boostablexp or action.xp --used for mahogany homes (and pyre logs), which has reward xp that is not boostable by the outfit and xp for making the items in the house which can be boosted (pyre logs are unaffected by the pyro outfit)&lt;br /&gt;
	if options[&amp;#039;bonus&amp;#039;] and otherBonuses[options[&amp;#039;bonus&amp;#039;]] and action.type == &amp;#039;Regular&amp;#039; then&lt;br /&gt;
		local value = otherBonuses[options[&amp;#039;bonus&amp;#039;]]&lt;br /&gt;
		actionExperience = (helpers.jagexFloor(helpers.jagexFloor((boostablexp * value) * options.setValue, 1) + (action.xp * value), 1)) * options.leagueMultiplier&lt;br /&gt;
	else&lt;br /&gt;
		actionExperience = (helpers.jagexFloor(boostablexp * options.setValue, 1) + action.xp) * options.leagueMultiplier&lt;br /&gt;
	end&lt;br /&gt;
	local numberOfActionsNeeded = math.ceil(options.experienceRemaining / actionExperience)&lt;br /&gt;
	local members = helpers.membersIcon(action.members)&lt;br /&gt;
	local materials = spreadMaterials(action.materials, numberOfActionsNeeded)&lt;br /&gt;
	local inputCost = getInputCost(action.materials, numberOfActionsNeeded)&lt;br /&gt;
	if ({ Prayer = true })[skill] then&lt;br /&gt;
		inputCost = inputCost + (serviceFeeValues[options[&amp;#039;unnotingService&amp;#039;]] * numberOfActionsNeeded)&lt;br /&gt;
	end&lt;br /&gt;
	local gpXp = numberOfActionsNeeded == 0 and 0 or (-inputCost / actionExperience) / numberOfActionsNeeded&lt;br /&gt;
	local materialsOverride = &amp;#039;&amp;#039;&lt;br /&gt;
	if materials == &amp;#039;-&amp;#039; then&lt;br /&gt;
		materialsOverride = { [&amp;#039;text-align&amp;#039;] = &amp;#039;center&amp;#039; }&lt;br /&gt;
	end&lt;br /&gt;
    local namestr = action.title and &amp;#039;[[&amp;#039; .. action.name .. &amp;#039;|&amp;#039; .. action.title .. &amp;#039;]]&amp;#039; or &amp;#039;[[&amp;#039; .. action.name .. &amp;#039;]]&amp;#039;&lt;br /&gt;
    namestr = action.subtxt and string.format(&amp;#039;%s &amp;lt;br /&amp;gt;&amp;lt;small&amp;gt;(%s)&amp;lt;/small&amp;gt;&amp;#039;, namestr, action.subtxt) or namestr&lt;br /&gt;
&lt;br /&gt;
	return mw.html.create(&amp;#039;tr&amp;#039;):addClass(rowColor)&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(&amp;#039;[[File:&amp;#039; .. picture .. &amp;#039;.png|link=&amp;#039; .. action.name .. &amp;#039;]]&amp;#039;):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(namestr):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(action.level or 1):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(commas(actionExperience)):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(commas(numberOfActionsNeeded)):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):css(materialsOverride):wikitext(materials):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(coins(commas(inputCost))):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(coins(commas(gpXp))):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(members):done()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function make_row_full(action, options)&lt;br /&gt;
	local outputQuantity, actionExperience, numberOfActionsNeeded&lt;br /&gt;
	local rowColor = options.dataCriteria == &amp;#039;Greyed out&amp;#039; and helpers.isRowGrey(action.level, options.currentLevel) or &amp;#039;&amp;#039;&lt;br /&gt;
	local picture = action.pic or action.name&lt;br /&gt;
	local compostInfo = compostValues[options[&amp;#039;compost&amp;#039;]]&lt;br /&gt;
	local compostLife = compostInfo and compostInfo[1] or 0&lt;br /&gt;
	local compostXp = compostInfo and compostInfo[2] or 0&lt;br /&gt;
	local reducedNumberOfActions&lt;br /&gt;
	if options[&amp;#039;skill&amp;#039;] == &amp;#039;Farming&amp;#039; and farmingCTS[action.name] then&lt;br /&gt;
		local itemBonus = generateItemBonus(options, action.type, action.name)&lt;br /&gt;
		local otherBonus = generateOtherBonus(options, action.type)&lt;br /&gt;
		local harvestLives = 3 + compostLife&lt;br /&gt;
		mw.log(action.name)&lt;br /&gt;
		local estimatedYield = generateEstimatedYield(options.currentLevel, farmingCTS[action.name], harvestLives, itemBonus, otherBonus)&lt;br /&gt;
		-- action.xp possible multiplied first here as well for the league multiplier?&lt;br /&gt;
		local combinedXp = helpers.jagexFloor(estimatedYield * action.xp + (action.plantXp and action.plantXp or 0) + (action.healthXp and action.healthXp or 0) + compostXp, 1)&lt;br /&gt;
		actionExperience = (helpers.jagexFloor(combinedXp * options.setValue, 1) + combinedXp) * options.leagueMultiplier&lt;br /&gt;
		numberOfActionsNeeded = math.ceil(options.experienceRemaining / actionExperience)&lt;br /&gt;
		reducedNumberOfActions = numberOfActionsNeeded / estimatedYield&lt;br /&gt;
		outputQuantity = estimatedYield&lt;br /&gt;
	elseif action.assumedYield then&lt;br /&gt;
		local combinedXp = helpers.jagexFloor(action.assumedYield * action.xp + (action.plantXp and action.plantXp or 0) + (action.healthXp and action.healthXp or 0) + compostXp, 1)&lt;br /&gt;
		actionExperience = (helpers.jagexFloor(combinedXp * options.setValue, 1) + combinedXp) * options.leagueMultiplier&lt;br /&gt;
		numberOfActionsNeeded = math.ceil(options.experienceRemaining / actionExperience)&lt;br /&gt;
		reducedNumberOfActions = numberOfActionsNeeded / action.assumedYield&lt;br /&gt;
		outputQuantity = action.assumedYield&lt;br /&gt;
	else&lt;br /&gt;
		actionExperience = (helpers.jagexFloor(action.xp * options.setValue, 1) + action.xp + compostXp) * options.leagueMultiplier&lt;br /&gt;
		numberOfActionsNeeded = math.ceil(options.experienceRemaining / actionExperience)&lt;br /&gt;
		outputQuantity = action.outputQuantity and action.outputQuantity or 1&lt;br /&gt;
	end&lt;br /&gt;
	local members = helpers.membersIcon(action.members)&lt;br /&gt;
	local materials = spreadMaterials(action.materials, numberOfActionsNeeded, reducedNumberOfActions)&lt;br /&gt;
	local inputCost = getInputCost(action.materials, numberOfActionsNeeded, reducedNumberOfActions)&lt;br /&gt;
	local outputPrice = getOutputPrice(action.name, action.outputItem, outputQuantity, numberOfActionsNeeded, reducedNumberOfActions)&lt;br /&gt;
	local profitLoss = outputPrice - inputCost&lt;br /&gt;
	local gpXp = numberOfActionsNeeded == 0 and 0 or ((profitLoss) / actionExperience) / numberOfActionsNeeded&lt;br /&gt;
	local materialsOverride = &amp;#039;&amp;#039;&lt;br /&gt;
	if materials == &amp;#039;-&amp;#039; then&lt;br /&gt;
		materialsOverride = { [&amp;#039;text-align&amp;#039;] = &amp;#039;center&amp;#039; }&lt;br /&gt;
	end&lt;br /&gt;
    local namestr = action.title and &amp;#039;[[&amp;#039; .. action.name .. &amp;#039;|&amp;#039; .. action.title .. &amp;#039;]]&amp;#039; or &amp;#039;[[&amp;#039; .. action.name .. &amp;#039;]]&amp;#039;&lt;br /&gt;
    namestr = action.subtxt and string.format(&amp;#039;%s &amp;lt;br /&amp;gt;&amp;lt;small&amp;gt;(%s)&amp;lt;/small&amp;gt;&amp;#039;, namestr, action.subtxt) or namestr&lt;br /&gt;
&lt;br /&gt;
	return mw.html.create(&amp;#039;tr&amp;#039;):addClass(rowColor)&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(&amp;#039;[[File:&amp;#039; .. picture .. &amp;#039;.png|link=&amp;#039; .. action.name .. &amp;#039;]]&amp;#039;):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(namestr):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(action.level or 1):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(commas(actionExperience)):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(commas(numberOfActionsNeeded)):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):css(materialsOverride):wikitext(materials):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(coins(commas(inputCost))):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(coins(commas(outputPrice))):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(coins(commas(profitLoss))):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(coins(commas(gpXp))):done()&lt;br /&gt;
		:tag(&amp;#039;td&amp;#039;):wikitext(members):done()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function generateEstimatedYield(level, values, harvestLives, itemBonus, otherBonus)&lt;br /&gt;
	local chanceValues = math.floor((values[1] * (99 - level) / 98) + (values[2] * (level - 1) / 98))&lt;br /&gt;
	local itemBonuses = 1 + itemBonus&lt;br /&gt;
	local otherBonuses = 1 + otherBonus&lt;br /&gt;
	local chanceToSave = (math.floor(math.floor(chanceValues * itemBonuses) * otherBonuses) + 1) / 256&lt;br /&gt;
	local expectedYield = harvestLives / (1 - chanceToSave)&lt;br /&gt;
	&lt;br /&gt;
	return expectedYield&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function generateItemBonus(options, type, name)&lt;br /&gt;
	local itemBonus = 0&lt;br /&gt;
	&lt;br /&gt;
	if options == nil then&lt;br /&gt;
		return itemBonus&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for i, v in next, options, nil do&lt;br /&gt;
		if itemBonuses[i] and v == &amp;#039;true&amp;#039; then&lt;br /&gt;
			if i == &amp;#039;farmingCape&amp;#039; then&lt;br /&gt;
				if type == &amp;#039;Herb&amp;#039; then&lt;br /&gt;
					itemBonus = itemBonus + tonumber(itemBonuses[i])&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				local usedFor = { Herb = true, Allotment = true, Hops = true, Special = true }&lt;br /&gt;
				local doNotCalculate = { [&amp;#039;Giant seaweed&amp;#039;] = true, [&amp;#039;Cactus spine&amp;#039;] = true, [&amp;#039;Potato cactus&amp;#039;] = true }&lt;br /&gt;
				if usedFor[type] and not doNotCalculate[name] then&lt;br /&gt;
					itemBonus = itemBonus + tonumber(itemBonuses[i])&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return itemBonus&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function generateOtherBonus(options, type)&lt;br /&gt;
	local otherBonus = 0&lt;br /&gt;
	&lt;br /&gt;
	if options == nil then&lt;br /&gt;
		return otherBonus&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for i, v in next, options, nil do&lt;br /&gt;
		if otherBonuses[i] then&lt;br /&gt;
			if i == &amp;#039;diary&amp;#039; then&lt;br /&gt;
				if type == &amp;#039;Herb&amp;#039; then&lt;br /&gt;
					otherBonus = otherBonus + tonumber(otherBonuses[i][v])&lt;br /&gt;
				end&lt;br /&gt;
			elseif v == &amp;#039;true&amp;#039; then&lt;br /&gt;
				otherBonus = otherBonus + tonumber(otherBonuses[i])&lt;br /&gt;
			elseif v ~= &amp;#039;false&amp;#039; then&lt;br /&gt;
				otherBonus = otherBonus + tonumber(otherBonuses[i][v])&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return otherBonus&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Alex</name></author>
	</entry>
</feed>