Module:Chambers of Xeric calculator

From Roat Pkz
Revision as of 12:49, 6 May 2024 by Hefner (talk | contribs) (Created page with "local geprice = require('Module:Exchange')._price local coins = require('Module:Coins')._amount local commas = require('Module:Addcommas')._add local p = {} local uniqueItems = { {name = "Arcane prayer scroll", weight = 20}, {name = "Dexterous prayer scroll", weight = 20}, {name = "Dragon hunter crossbow", weight = 4}, {name = "Twisted buckler", weight = 4}, {name = "Dinh's bulwark", weight = 3}, {name = "Ancestral hat", weight = 3}, {name = "Ancestral robe bott...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Documentation for this module may be created at Module:Chambers of Xeric calculator/doc

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

local p = {}

local uniqueItems = {
	{name = "Arcane prayer scroll", weight = 20},
	{name = "Dexterous prayer scroll", weight = 20},
	{name = "Dragon hunter crossbow", weight = 4},
	{name = "Twisted buckler", weight = 4},
	{name = "Dinh's bulwark", weight = 3},
	{name = "Ancestral hat", weight = 3},
	{name = "Ancestral robe bottom", weight = 3},
	{name = "Ancestral robe top", weight = 3},
	{name = "Dragon claws", weight = 3},
	{name = "Elder maul", weight = 2},
	{name = "Kodai insignia", weight = 2},
	{name = "Twisted bow", weight = 2}
}

local trashItems = {
	{name = "Death rune", divisor = 36},
	{name = "Blood rune", divisor = 32},
	{name = "Soul rune", divisor = 20},
	{name = "Rune arrow", divisor = 14},
	{name = "Dragon arrow", divisor = 202},
	{name = "Grimy ranarr weed", divisor = 788},
	{name = "Grimy toadflax", divisor = 520},
	{name = "Grimy irit leaf", divisor = 162},
	{name = "Grimy avantoe", divisor = 324},
	{name = "Grimy kwuarm", divisor = 378},
	{name = "Grimy snapdragon", divisor = 1300},
	{name = "Grimy cadantine", divisor = 330},
	{name = "Grimy lantadyme", divisor = 248},
	{name = "Grimy dwarf weed", divisor = 200},
	{name = "Grimy torstol", divisor = 810},
	{name = "Silver ore", divisor = 20},
	{name = "Coal", divisor = 20},
	{name = "Gold ore", divisor = 44},
	{name = "Mithril ore", divisor = 32},
	{name = "Adamantite ore", divisor = 166},
	{name = "Runite ore", divisor = 2000},
	{name = "Uncut sapphire", divisor = 188},
	{name = "Uncut emerald", divisor = 142},
	{name = "Uncut ruby", divisor = 242},
	{name = "Uncut diamond", divisor = 508},
	{name = "Lizardman fang", divisor = 28},
	{name = "Pure essence", divisor = 2},
	{name = "Saltpetre", divisor = 24},
	{name = "Teak plank", divisor = 96},
	{name = "Mahogany plank", divisor = 238},
	{name = "Dynamite", divisor = 54},
	{name = "Torn prayer scroll", divisor = 1},
	{name = "Dark relic", divisor = 1}
}

function p.main(frame)
	local args = frame:getParent().args
	args.teamSize = tonumber(args.teamSize) or 1
	args.timeTaken = tonumber(args.timeTaken) or ''
	args.personalPoints = tonumber(args.personalPoints) or 0
	args.groupPoints = tonumber(args.groupPoints) or 0
	if args.personalPoints > args.groupPoints then
		return "You can't have more personal points than group points!"
	end

	if args.groupPoints == 0 then
		return "You get nothing, because your team got zero points. Try the [[Theatre of Blood]] instead — you might at least get a cabbage out of it."
	end
	
	local relevantPoints = math.min(570000*6, args.groupPoints)
	local maxPossibleUniqueRolls = math.min(6, math.ceil(relevantPoints / 570000))
	
	-- rather do this than a nasty for loop
	local uniquesLine = ""
	if maxPossibleUniqueRolls == 1 then
		uniquesLine = string.format("Your team will get one chance to hit the unique table, with a '''%.2f%%''' chance of success.", relevantPoints/8675)
	elseif maxPossibleUniqueRolls == 2 then
		uniquesLine = string.format("Your team will get two chances to hit the unique table, with a '''%.2f%%''' and '''%.2f%%''' chance of success respectively.",
			570000/8675, (relevantPoints-570000*1)/8675)
	elseif maxPossibleUniqueRolls == 3 then
		uniquesLine = string.format("Your team will get three chances to hit the unique table, with a '''%.2f%%''', '''%.2f%%''' and '''%.2f%%''' chance of success respectively.",
			570000/8675, 570000/8675, (relevantPoints-570000*2)/8675)
	elseif maxPossibleUniqueRolls == 4 then
		uniquesLine = string.format("Your team will get four chances to hit the unique table, with a '''%.2f%%''', '''%.2f%%''', '''%.2f%%''' and '''%.2f%%''' chance of success respectively.",
			570000/8675, 570000/8675, 570000/8675, (relevantPoints-570000*3)/8675)
	elseif maxPossibleUniqueRolls == 5 then
		uniquesLine = string.format("Your team will get five chances to hit the unique table, with a '''%.2f%%''', '''%.2f%%''', '''%.2f%%''', '''%.2f%%''' and '''%.2f%%''' chance of success respectively.",
			570000/8675, 570000/8675, 570000/8675, 570000/8675, (relevantPoints-570000*4)/8675)
	elseif maxPossibleUniqueRolls == 6 then
		uniquesLine = string.format("Your team will get six chances to hit the unique table, with a '''%.2f%%''', '''%.2f%%''', '''%.2f%%''', '''%.2f%%''', '''%.2f%%''' and '''%.2f%%''' chance of success respectively.",
			570000/8675, 570000/8675, 570000/8675, 570000/8675, 570000/8675, (relevantPoints-570000*5)/8675)
	end
	
	local uniquesTable = mw.html.create('table')
	uniquesTable:addClass('wikitable')
	uniquesTable:addClass('align-center-1')
	:tag('tr')
		:tag('th')
			:wikitext('Item')
			:attr('colspan', 2)
		:done()
		:tag('th')
			:wikitext('Price')
		:done()
		:tag('th')
			:wikitext('Expected per team')
		:done()
		:tag('th')
			:wikitext('Expected personal value')
		:done()

	local expectedRolls = math.min(570000*6, relevantPoints) / 867500
	local personalRatio = args.personalPoints / args.groupPoints -- for this particular calculation we care about the actual points scored by the team
	local totalUniqueExpectation = 0.0

	if args.split == 'yes' then
		personalRatio = 1 / args.teamSize
	end

	for _, unique in ipairs(uniqueItems) do
		local price = geprice(unique.name)
		local expectation = expectedRolls * unique.weight / 69
		totalUniqueExpectation = totalUniqueExpectation + price * expectation * personalRatio
		uniquesTable:tag('tr')
			:tag('td')
				:wikitext(string.format('[[File:%s.png|link=%s]]', unique.name, unique.name))
			:done()
			:tag('td')
				:wikitext(string.format('[[%s]]', unique.name))
			:done()
			:tag('td')
				:wikitext(coins(price))
			:done()
			:tag('td')
				:wikitext(string.format('%.3f%%', 100 * expectation ))
			:done()	
			:tag('td')
				:wikitext(coins(price * expectation * personalRatio))
			:done()
	end
	
	uniquesTable:tag('tr')
		:tag('th')
			:attr('colspan', 4)
		:done()
		:tag('th')
			:wikitext(coins(totalUniqueExpectation))
		:done()
	
	local trashLine = string.format("Failing a unique roll, you will get two rolls on the resource table, based on your '''%s''' points.", commas(args.personalPoints))

	local trashTable = mw.html.create('table')
	trashTable:addClass('wikitable')
	trashTable:addClass('align-center-1')
	:tag('tr')
		:tag('th')
			:wikitext('Item')
			:attr('colspan', 2)
		:done()
		:tag('th')
			:wikitext('Quantity')
		:done()
		:tag('th')
			:wikitext('Price')
		:done()
		:tag('th')
			:wikitext('Expected per chest')
		:done()
		:tag('th')
			:wikitext('Expected personal value')
		:done()	
	
	local totalTrashExpectation = 0.0
	for _, trash in ipairs(trashItems) do
		local price = 0
		if trash.name ~= "Dark relic" then
			price = geprice(trash.name)
		end
		local quantity = math.floor(args.personalPoints / trash.divisor)
		if trash.name == "Torn prayer scroll" or trash.name == "Dark relic" then
			quantity = 1
		end
		local expectedCount = (1 - args.personalPoints / args.groupPoints * expectedRolls) * 2 * quantity / #trashItems
		totalTrashExpectation = totalTrashExpectation + expectedCount * price
		trashTable:tag('tr')
			:tag('td')
				:wikitext(string.format('[[File:%s.png|link=%s]]', trash.name, trash.name))
			:done()
			:tag('td')
				:wikitext(string.format('[[%s]]', trash.name))
			:done()
			:tag('td')
				:wikitext(quantity)
			:done()
			:tag('td')
				:wikitext(coins(price))
			:done()
			:tag('td')
				:wikitext(string.format('%.2f', expectedCount ))
			:done()	
			:tag('td')
				:wikitext(coins(price * expectedCount))
			:done()		
	end
	
	trashTable:tag('tr')
		:tag('th')
			:attr('colspan', 5)
		:done()
		:tag('th')
			:wikitext(coins(totalTrashExpectation))
		:done()
	
	local totalExpectation = totalTrashExpectation + totalUniqueExpectation
	local mainLine = string.format("You got '''%s''' points and your team of '''%d''' got '''%s''' points.", commas(args.personalPoints), args.teamSize, commas(args.groupPoints))
	parenthetical = "free-for-all"
	if args.split == 'yes' then
		parenthetical = "even splits"
	end
	mainLine = mainLine .. string.format(" This gives a total expected value for your personal chest (including %s on uniques), of '''%s'''.", parenthetical, coins(totalExpectation))
	
	if args.timeTaken ~= '' then
		mainLine = mainLine .. string.format(" At %d minutes a raid, that makes Chambers of Xeric about '''%s''' per hour in the long run.", args.timeTaken, coins(totalExpectation * 60 / args.timeTaken))
	end
	return mainLine .. '\n\n' .. uniquesLine .. '\n\n' .. tostring(uniquesTable) .. '\n\n' .. trashLine .. '\n\n' .. tostring(trashTable)
end

return p