Module:Wintertodt supply crate

From RuneRealm Wiki

This is the current revision of this page, as edited by Alex (talk | contribs) at 00:13, 17 October 2024 (Created page with "local geprice = require('Module:Exchange')._price local coins = require('Module:Coins')._amount local p = {} local items = {} items.crafting = { {name="Uncut diamond", minQty=1, maxQty=3, lowRoll=10, highRoll=120}, {name="Uncut ruby", minQty=2, maxQty=4, lowRoll=50, highRoll=140}, {name="Uncut emerald", minQty=1, maxQty=3, lowRoll=90, highRoll=160}, {name="Uncut sapphire", minQty=1, maxQty=3, lowRoll=255, highRoll=255}, } items.herblore = { {name="Grimy torstol"..."). The present address (URL) is a permanent link to this version.

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
Module documentation
This documentation is transcluded from Template:No documentation/doc. [edit] [history] [purge]
This module does not have any documentation. Please consider adding documentation at Module:Wintertodt supply crate/doc. [edit]
Module:Wintertodt supply crate's function main is invoked by Calculator:Wintertodt Reward Cart.
Module:Wintertodt supply crate requires Module:Coins.
Module:Wintertodt supply crate requires Module:Exchange.

local geprice = require('Module:Exchange')._price
local coins = require('Module:Coins')._amount

local p = {}

local items = {}

items.crafting = {
	{name="Uncut diamond", minQty=1, maxQty=3, lowRoll=10, highRoll=120},
	{name="Uncut ruby", minQty=2, maxQty=4, lowRoll=50, highRoll=140},
	{name="Uncut emerald", minQty=1, maxQty=3, lowRoll=90, highRoll=160},
	{name="Uncut sapphire", minQty=1, maxQty=3, lowRoll=255, highRoll=255},
}

items.herblore = {
	{name="Grimy torstol", minQty=1, maxQty=3, lowRoll=-70, highRoll=40},
	{name="Grimy dwarf weed", minQty=2, maxQty=4, lowRoll=-50, highRoll=50},
	{name="Grimy lantadyme", minQty=2, maxQty=4, lowRoll=-30, highRoll=60},
	{name="Grimy cadantine", minQty=2, maxQty=4, lowRoll=-10, highRoll=70},
	{name="Grimy kwuarm", minQty=2, maxQty=4, lowRoll=10, highRoll=85},
	{name="Grimy avantoe", minQty=3, maxQty=5, lowRoll=20, highRoll=100},
	{name="Grimy irit leaf", minQty=3, maxQty=5, lowRoll=30, highRoll=115},
	{name="Grimy ranarr weed", minQty=1, maxQty=3, lowRoll=10, highRoll=170},
	{name="Grimy tarromin", minQty=3, maxQty=6, lowRoll=70, highRoll=-20},
	{name="Grimy marrentill", minQty=3, maxQty=6, lowRoll=100, highRoll=-30},
	{name="Grimy guam leaf", minQty=3, maxQty=6, lowRoll=170, highRoll=-40},
	{name="Grimy harralander", minQty=3, maxQty=6, lowRoll=255, highRoll=255},
}

items.farming = {
	{name="Spirit seed", minQty=1, maxQty=1, lowRoll=-20, highRoll=5},
	{name="Dwarf weed seed", minQty=1, maxQty=3, lowRoll=-60, highRoll=25},
	{name="Lantadyme seed", minQty=1, maxQty=3, lowRoll=-60, highRoll=30},
	{name="Cadantine seed", minQty=1, maxQty=3, lowRoll=-40, highRoll=40},
	{name="Snapdragon seed", minQty=1, maxQty=3, lowRoll=-15, highRoll=60},
	{name="Yew seed", minQty=1, maxQty=2, lowRoll=-10, highRoll=70},
	{name="Snape grass seed", minQty=3, maxQty=7, lowRoll=-8, highRoll=78},
	{name="Kwuarm seed", minQty=1, maxQty=3, lowRoll=-10, highRoll=80},
	{name="Ranarr seed", minQty=1, maxQty=3, lowRoll=0, highRoll=110},
	{name="Avantoe seed", minQty=1, maxQty=3, lowRoll=0, highRoll=130},
	{name="Watermelon seed", minQty=3, maxQty=7, lowRoll=-10, highRoll=180},
	{name="Irit seed", minQty=1, maxQty=3, lowRoll=0, highRoll=170},
	{name="Teak seed", minQty=1, maxQty=2, lowRoll=10, highRoll=160},
	{name="Maple seed", minQty=1, maxQty=2, lowRoll=15, highRoll=190},
	{name="Mahogany seed", minQty=1, maxQty=2, lowRoll=20, highRoll=190},
	{name="Toadflax seed", minQty=1, maxQty=3, lowRoll=20, highRoll=190},
	{name="Banana tree seed", minQty=1, maxQty=2, lowRoll=30, highRoll=180},
	{name="Willow seed", minQty=1, maxQty=2, lowRoll=60, highRoll=120},
	{name="Harralander seed", minQty=1, maxQty=3, lowRoll=80, highRoll=-150},
	{name="Tarromin seed", minQty=1, maxQty=3, lowRoll=150, highRoll=-150},
	{name="Acorn", minQty=1, maxQty=1, lowRoll=255, highRoll=255},
}

items.woodcutting = {
	{name="Magic logs", minQty=10, maxQty=20, lowRoll=-60, highRoll=60},
	{name="Yew logs", minQty=10, maxQty=20, lowRoll=-50, highRoll=90},
	{name="Mahogany logs", minQty=10, maxQty=20, lowRoll=-40, highRoll=130},
	{name="Maple logs", minQty=10, maxQty=20, lowRoll=0, highRoll=160},
	{name="Teak logs", minQty=10, maxQty=20, lowRoll=30, highRoll=200},
	{name="Willow logs", minQty=10, maxQty=20, lowRoll=120, highRoll=100},
	{name="Oak logs", minQty=10, maxQty=20, lowRoll=255, highRoll=255},
}

items.mining = {
	{name="Runite ore", minQty=1, maxQty=2, lowRoll=-60, highRoll=40},
	{name="Adamantite ore", minQty=2, maxQty=3, lowRoll=-50, highRoll=80},
	{name="Mithril ore", minQty=3, maxQty=5, lowRoll=-20, highRoll=140},
	{name="Gold ore", minQty=8, maxQty=11, lowRoll=0, highRoll=160},
	{name="Coal", minQty=10, maxQty=14, lowRoll=0, highRoll=180},
	{name="Pure essence", minQty=20, maxQty=70, lowRoll=40, highRoll=190},
	{name="Silver ore", minQty=10, maxQty=12, lowRoll=140, highRoll=10},
	{name="Limestone", minQty=2, maxQty=7, lowRoll=200, highRoll=-20},
	{name="Iron ore", minQty=5, maxQty=15, lowRoll=255, highRoll=255},
}

items.fishing = {
	{name="Raw shark", minQty=6, maxQty=11, lowRoll=-60, highRoll=80},
	{name="Raw swordfish", minQty=6, maxQty=11, lowRoll=-50, highRoll=100},
	{name="Raw lobster", minQty=6, maxQty=11, lowRoll=-20, highRoll=130},
	{name="Raw tuna", minQty=6, maxQty=11, lowRoll=10, highRoll=160},
	{name="Raw salmon", minQty=6, maxQty=11, lowRoll=40, highRoll=180},
	{name="Raw anchovies", minQty=6, maxQty=11, lowRoll=160, highRoll=0},
	{name="Raw trout", minQty=6, maxQty=11, lowRoll=255, highRoll=255},
}

items.other = {
	{name="Coins", minQty=2000, maxQty=4999, chance=5/25, price=1},
	{name="Dynamite", minQty=3, maxQty=5, chance=1/25, price=geprice("Dynamite")},
	{name="Saltpetre", minQty=3, maxQty=5, chance=1/25, price=geprice("Saltpetre")},
}

function p.interpolate(skillLevel, lowRoll, highRoll)
	local unclamped = math.floor(lowRoll + (highRoll - lowRoll) * (skillLevel - 1) / 98)
	return math.min(math.max(unclamped+1, 0), 256)
end

function p.main(frame)
	args = frame.args
	
	local skills = {
		crafting = tonumber(args.crafting),
		farming = tonumber(args.farming),
		fishing = tonumber(args.fishing),
		herblore = tonumber(args.herblore),
		mining = tonumber(args.mining),
		woodcutting = tonumber(args.woodcutting),
	}
	return p._main(tonumber(args.points), skills, 
		args.hasPhoenix=='yes', args.magicEligible=='yes',
		args.torstolEligible=='yes', args.sellPyro=='yes')
end

function makeLine(name, minQty, maxQty, chancePerRoll, rolls, price)
	local expectedCount = rolls * chancePerRoll * (minQty + maxQty) / 2
	local qtyRange = tostring(minQty)
	if minQty ~= maxQty then
		qtyRange = tostring(minQty) .. '-' .. tostring(maxQty)
	end
	
	local displayName = name
	if name == "Pyromancer hood" then
		displayName = "Pyromancer outfit|Pyromancer outfit piece"
	end

	return mw.html.create('tr')
		:tag('td')
			:wikitext('[[File:' .. name .. '.png|link=' .. name .. ']]')
		:done()
		:tag('td')
			:wikitext('[[' .. displayName .. ']]')
		:done()
		:tag('td')
			:wikitext(qtyRange)
		:done()
		:tag('td')
			:wikitext(coins(price))
		:done()
		:tag('td')
			:wikitext(string.format('%.3f%%', 100 * chancePerRoll))
		:done()
		:tag('td')
			:wikitext(string.format('%.3f', expectedCount))
		:done()
		:tag('td')
			:wikitext(coins(tostring(price * expectedCount) .. '/ 1'))
		:done()
end
	
function p._main(points, skills, hasPhoenix, magicEligible, torstolEligible, sellPyro)
	if points < 500 then
		return "You can't get rewards with less than 500 points."
	end
	local rolls = 1 + points / 500

	local uniquesExpectation = 0
	local uniquesTable = mw.html.create('table')
	uniquesTable:addClass('wikitable sortable align-center-1 align-left-2 align-left-3'):css('text-align','right')
	
	local header = mw.html.create('tr')
		:tag('th')
			:wikitext('Item')
			:attr('colspan', 2)
		:done()
		:tag('th')
			:wikitext('Quantity<br/>(per roll)')
		:done()
		:tag('th')
			:wikitext('Price')
		:done()
		:tag('th')
			:wikitext('Chance<br/>(per roll)')
		:done()
		:tag('th')
			:wikitext('Expected<br/>(per run)')
		:done()
		:tag('th')
			:wikitext('Expected value')
		:done()
	
	uniquesTable:node(header)

	local totalProbability = 1.0
	if not hasPhoenix then
		uniquesTable:node(makeLine("Phoenix", 1, 1, 1/5000, rolls, 0))
		totalProbability = totalProbability * (1 - 1/5000)
	end
	
	uniquesTable:node(makeLine("Dragon axe", 1, 1, 1/10000 * totalProbability, rolls, geprice("Dragon axe")))
	uniquesExpectation = uniquesExpectation + 1/10000 * totalProbability * rolls * geprice("Dragon axe")
	totalProbability = totalProbability * (1 - 1/10000)

	uniquesTable:node(makeLine("Tome of fire (empty)", 1, 1, 1/1000 * totalProbability, rolls, geprice("Tome of fire (empty)")))
	uniquesExpectation = uniquesExpectation + 1/1000 * totalProbability * rolls * geprice("Tome of fire (empty)")
	totalProbability = totalProbability * (1 - 1/1000)
	
	if magicEligible then
		uniquesTable:node(makeLine("Magic seed", 1, 1, 1/150 * totalProbability, rolls, geprice("Magic seed")))
		uniquesExpectation = uniquesExpectation + 1/150 * totalProbability * rolls * geprice("Magic seed")
	else
		uniquesTable:node(makeLine("Warm gloves", 1, 1, 1/150 * totalProbability, rolls, 0))
	end
	totalProbability = totalProbability * (1 - 1/150)
	
	if torstolEligible then
		uniquesTable:node(makeLine("Torstol seed", 2, 3, 1/150 * totalProbability, rolls, geprice("Torstol seed")))
		uniquesExpectation = uniquesExpectation + 1/150 * totalProbability * rolls * geprice("Torstol seed") * 2.5
	else
		uniquesTable:node(makeLine("Bruma torch", 1, 1, 1/150 * totalProbability, rolls, 0))
	end
	totalProbability = totalProbability * (1 - 1/150)
	
	local pyroPrice = 0
	if sellPyro then
		pyroPrice = geprice("Burnt page") * 50
	end
	uniquesTable:node(makeLine("Pyromancer hood", 1, 1, 1/150 * totalProbability, rolls, pyroPrice))
	uniquesExpectation = uniquesExpectation + 1/150 * totalProbability * rolls * pyroPrice
	totalProbability = totalProbability * (1 - 1/150)
	
	uniquesTable:node(makeLine("Burnt page", 7, 29, 1/45 * totalProbability, rolls, geprice("Burnt page")))
	uniquesExpectation = uniquesExpectation + 1/45 * totalProbability * rolls * geprice("Burnt page") * 18
	totalProbability = totalProbability * (1 - 1/45)

	uniquesTable:tag('tr')
		:tag('th')
			:attr('colspan', 6)
			:css('text-align','right')
			:wikitext('Total:')
		:done()
		:tag('td')
			:css('text-align','right')
			:wikitext(coins(tostring(uniquesExpectation) .. '/1'))
		:done()

	local resourcesTable = mw.html.create('table')
	resourcesTable:addClass('wikitable sortable align-center-1 align-left-2 align-left-3'):css('text-align','right')
		:node(header)
	
	local resourcesExpectation = 0
	for skill, skillLevel in pairs(skills) do
		local remainingProbability = 1.0
		for _, item in ipairs(items[skill]) do
			local subchance = p.interpolate(skillLevel, item.lowRoll, item.highRoll) / 256
			local chancePerRoll = remainingProbability * subchance
			remainingProbability = remainingProbability - chancePerRoll
			chancePerRoll = chancePerRoll * totalProbability
			
			local price = 0
			if item.name ~= 'Spirit seed' then
				price = geprice(item.name)
			end
			local expectedCount = chancePerRoll * rolls * 3/25 * (item.minQty + item.maxQty) / 2
			resourcesExpectation = resourcesExpectation + expectedCount * price
			
			local row = makeLine(item.name, item.minQty, item.maxQty, chancePerRoll * 3/25, rolls, price)
			resourcesTable:node(row)
		end
	end
	
	for _, item in ipairs(items.other) do
		local expectedCount = (item.minQty + item.maxQty) / 2 * item.chance
		resourcesExpectation = resourcesExpectation + expectedCount * item.price
		local row = makeLine(item.name, item.minQty, item.maxQty, item.chance, rolls, item.price)
		resourcesTable:node(row)
	end

	resourcesTable:tag('tr')
		:tag('th')
			:attr('colspan', 6)
			:css('text-align','right')
			:wikitext('Total:')
		:done()
		:tag('td')
			:css('text-align','right')
			:wikitext(coins(tostring(resourcesExpectation) .. '/1'))
		:done()

	local rollsLine = "'''" 
	.. tostring(points) 
	.. "''' points in Wintertodt will give you in average '''"
	.. string.format('%.3f', rolls) 
	.. "''' rewards added to your reward pile. Ignoring untradeables, the total expected value of a run is '''"
	.. coins(uniquesExpectation + resourcesExpectation)
	.. "''' coins."
	mw.log(rollsLine .. '\n\n==Uniques==\n' .. tostring(uniquesTable) .. '\n\n==Resources==\n' .. tostring(resourcesTable))
	return rollsLine .. '\n\n==Uniques==\n' .. tostring(uniquesTable) .. '\n\n==Resources==\n' .. tostring(resourcesTable)
		
end

return p