Module:Slayer weight calculator

From WIDEVERSE Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Slayer weight calculator/doc

local Paramtest = require( 'Module:Paramtest' )
local Experience = require( 'Module:Experience' )
local Addcommas = require( 'Module:Addcommas' )
local Slayerlib = require ('Module:Slayer_weightings' )
local yn = require('Module:Yesno')

local p = {}

-- Slayer master mapping
local namemap = {
	['Turael/Spria'] = 'TuraelSpria',
	['Mazchna/Achtryn'] = 'MazchnaAchtryn',
	['Duradel/Lapalok'] = 'DuradelLapalok'
}

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


function p.tobool(str)
	if str == 'true' then
		return true
	end
	return false
end

function p.contains(tab,val)
	for index,value in ipairs(tab) do
      if value == val then 
         return true
      end
   end
   return false
end

function p.taskListContains(effectiveTable,val)
	for k,v in pairs(effectiveTable) do
		if v['name'] == val then
			return true
		end
	end
	return false
end

function p.main( args )
	local master = args.master
	if namemap[master] then
		master = namemap[master]
	end
	
	local slayerLevel, magicLevel, agilityLevel, defenceLevel, hitpointsLevel, strengthLevel, dungeoneeringLevel = Paramtest.defaults{
		{ tonumber(args.slayerLevel), 1 },
		{ tonumber(args.magicLevel), 1 },
		{ tonumber(args.agilityLevel), 1 },		
		{ tonumber(args.defenceLevel), 1 },
		{ tonumber(args.hitpointsLevel), 1 },
		{ tonumber(args.strengthLevel), 1 },		
		{ tonumber(args.dungeoneeringLevel), 1 },
	}

	local block1, block2, block3, block4, block5, block6, block7, block8 = Paramtest.defaults{
		{ args.block1, 'None'},
		{ args.block2, 'None'},
		{ args.block3, 'None'},
		{ args.block4, 'None'},
		{ args.block5, 'None'},
		{ args.block6, 'None'},
		{ args.block7, 'None'},
		{ args.block8, 'None'},
	}

	local blocks = {
		block1,
		block2,
		block3,
		block4,
		block5,
		block6,
		block7,
		block8
	}
	
	local prefer1, prefer2, prefer3, prefer4, prefer5, prefer6, prefer7, prefer8 = Paramtest.defaults{
		{ args.prefer1, 'None'},
		{ args.prefer2, 'None'},
		{ args.prefer3, 'None'},
		{ args.prefer4, 'None'},
		{ args.prefer5, 'None'},
		{ args.prefer6, 'None'},
		{ args.prefer7, 'None'},
		{ args.prefer8, 'None'},
	}

	local prefers = {
		prefer1,
		prefer2,
		prefer3,
		prefer4,
		prefer5,
		prefer6,
		prefer7,
		prefer8
	}
	
	-- Need to create a stats table, unlocks table, quests table, and other table
	local stats = {
		Slayer = slayerLevel,
		Magic = magicLevel,
		Dungeoneering = dungeoneeringLevel,
		Agility = agilityLevel,
		Defence = defenceLevel,
		Strength = strengthLevel,
		Hitpoints = hitpointsLevel
	}

	-- Here 0 means that you cannot get monsters as a result of this unlock
	-- Thus having stop the wyvern activated actually flips that value to 0
	-- since you can no longer get fossil island wyverns while it is active.
	local unlocks = { args.Aquanites, args.Muspahs, args.Nihils,
		args.Glacors, args.TormentedDemons, args.NightmareCreatures, 
		args.GWD, args.IceStryke, args.KaramjaTask, args.Prif, args.Mory,
		args.ancientCavern,
	}

	local quests = {
		args.FOTG,
		args.ROTM,
		args.WGS,
		args.ChildrenOfMah,
		args.POG,
		args.DAT,
		args.BOTD,
		args.Regicide,
		args.OoaK,
		args.TLW,
		args.BoD,
		args.WLB,
		args.Mogre,
		args.Ernest,
		args.Horror,
		args.Legends,
		args.Royal,
		args.Desert,
		args.Haunted,
		args.Cabin,
		args.Olaf,
		args.Rum,
		args.Death,
		args.LostCity,
		args.EW1,
		args.MEP2,
		args.Scabaras,
		args.Lunar,
		args.FairyTale2,
		args.Muspah,
		args.TWW,
		args.Bacon,
		args.Lucien
	}

	local other = {
		args.F2P
	}
	
	local vip = yn(args.vip)
	
	local cape = yn(args.cape)
	
	local hideZero = yn(args.hideZero)

	status = Slayerlib.create_status(stats, quests, unlocks, other, blocks)

	masterTable = Slayerlib.get_table(master)
	
	effectiveTable, unavailableTable = Slayerlib.get_effective_table(masterTable, status, true)
	
	local capeTask = 'None'
	
	--Ignores the task selected with the slayer master cape if it
	--can't be assigned by the current master or is on the block list
	if cape then
		cape = p.taskListContains(effectiveTable,args.capeTask)
		if cape then
			capeTask = args.capeTask
		end
	end
	
	local results = p.calculate_percents(effectiveTable, unavailableTable, vip, prefers, capeTask)
	return p.render_table(results, hideZero, vip)
end

function p.calculate_percents(effectiveTable, unavailableTable, vip, prefers, capeTask)
	--Create a sum of weights of available tasks
	local totalWeight = 0
	local preferWeight = 0
	
	for k, v in pairs(effectiveTable) do
		totalWeight = totalWeight + v['weight']
		if p.contains(prefers,v['name']) then 
    		preferWeight = preferWeight + v['weight']
		end
	end
	
	local capeChanceNo = 1
	
	if not(capeTask == 'None') then
		capeChanceNo = 0.8 --Chance of the slayer master cape NOT activating
	end

	local percentageTable = {}
	for k, v in pairs(effectiveTable) do
		local capeChanceYes = 0 
		if v['name']==capeTask then
			capeChanceYes = 0.2 --Chance of the slayer master cape activating
		end
		if p.contains(prefers,v['name']) then
			--In order, per task: name, chance of being assigned, icon, chance of being assigned with a vip tick, sum of assignment, weight
			--the weight is only used for vip ticket calculation
			--For a task on the prefer list, a second roll is made and it replaces the first roll if the first task is not on the vip list and the second task is
			table.insert(percentageTable, {v['name'], capeChanceNo*(v['weight']/totalWeight+(totalWeight-preferWeight)/totalWeight*v['weight']/totalWeight)+capeChanceYes,v['image'],0,0,v['weight']})
		else
			table.insert(percentageTable, {v['name'], capeChanceNo*(v['weight']/totalWeight*(1-(preferWeight)/totalWeight))+capeChanceYes,v['image'],0,0,v['weight']})
		end
	end
	for i=1,#percentageTable do
		local capeChanceYes = 0
		if percentageTable[i][1] == capeTask then
			capeChanceYes = 0.2
		end
		for j=1,#percentageTable do
			if not(i==j) then
				--the chance a task appears in the second slot is
				--the sum of (chance a different task appears in the first slot * chance the desired task appears in the second slot given that specificdifferent task is in the first slot)
				--summed over all other tasks
				--capeChance has to be subtracted because if the cape procs the second task is not rolled anyway
				percentageTable[j][4] = percentageTable[j][4] + (percentageTable[i][2]-capeChanceYes)*percentageTable[j][6]/(totalWeight-percentageTable[i][6]) 
			end
		end
	end
	
	--create a sum of chances of preferred tasks
	local preferSum = {0,0}
	for i=1,#percentageTable do
		if p.contains(prefers,percentageTable[i][1]) then
			preferSum[1] = preferSum[1] + percentageTable[i][2]
			preferSum[2] = preferSum[2] + percentageTable[i][4]
		end
	end

	--add blocked/unavailable tasks to the table
	for k, v in pairs(unavailableTable) do
		table.insert(percentageTable, {v['name'], 0,v['image'], 0,0})
	end
	
	--sort the table alphabetically
	table.sort(percentageTable, function(a,b) return a[1] < b[1] end)
	
	--add the sum of preferred tasks
	table.insert(percentageTable, {"Slayer points|Preferred task(s)", preferSum[1], "Slayer_points", preferSum[2], 0})
	
	--calculate sum of first and second slot chances for each table element
	for i=1,#percentageTable do
		percentageTable[i][5] = percentageTable[i][2]+percentageTable[i][4]
	end

	return percentageTable
end

function p.render_table(results, hideZero, vip)
	local resultsDiv = mw.html.create( 'div' )
	local resultsTable = mw.html.create( 'table' )
	if vip then
		resultsTable:addClass( 'wikitable' )
			:addClass( 'sortable align-center-1 align-center-2')
			:tag( 'tr' )
				:tag( 'th' )
					:wikitext( 'Results' )
					:attr( 'colspan', 5 )
				:done()
			:done()
			:tag( 'tr' )
				:tag( 'th' )
					:wikitext( 'Monster' )
					:attr( 'colspan', 2 )
				:done()
				:tag( 'th' )
					:wikitext( 'Assignment Chance (slot 1)')
				:done()
				:tag( 'th' )
					:wikitext( 'Assignment Chance (slot 2)')
				:done()
				:tag( 'th' )
					:wikitext( 'Assignment Chance (sum)')
				:done()
			:done()
		:done()
	else
		resultsTable:addClass( 'wikitable' )
			:addClass( 'sortable align-center-1 align-center-2')
			:tag( 'tr' )
				:tag( 'th' )
					:wikitext( 'Results' )
					:attr( 'colspan', 3 )
				:done()
			:done()
			:tag( 'tr' )
				:tag( 'th' )
					:wikitext( 'Monster' )
					:attr( 'colspan', 2 )
				:done()
				:tag( 'th' )
					:wikitext( 'Assignment Chance')
				:done()
			:done()
		:done()
	end

	for _, _v in ipairs(results) do
		if not vip then
			local k,v,i = _v[1], _v[2], _v[3]
			if not (hideZero and v == 0) then
				resultsTable:tag( 'tr' )
					:addClass( v == 0 and 'table-na' or nil )
					:tag( 'td' )
						:wikitext( (i ~= nil and i ~= '') and string.format("[[File:%s.png|link=%s]]", i, k) or nil )
						:attr('data-sort-value', k)
					:tag( 'td' )
						:wikitext( string.format("[[%s]]", k ) )
						:attr('data-sort-value', k)
					:done()
					:tag( 'td' )
						:wikitext( v==0 and "0%" or string.format("%.2f%%", 100*v ) )
						:css("text-align", "right")
						:attr('data-sort-value', v)
					:done()
				:done()
			end
		else
			local k,v,i,w,s = _v[1], _v[2], _v[3], _v[4], _v[5]
			if not (hideZero and v == 0) then
				resultsTable:tag( 'tr' )
					:addClass( v == 0 and 'table-na' or nil )
					:tag( 'td' )
						:wikitext( (i ~= nil and i ~= '') and string.format("[[File:%s.png|link=%s]]", i, k) or nil )
						:attr('data-sort-value', k)
					:tag( 'td' )
						:wikitext( string.format("[[%s]]", k ) )
						:attr('data-sort-value', k)
					:done()
					:tag( 'td' )
						:wikitext( v==0 and "0%" or string.format("%.2f%%", 100*v ) )
						:css("text-align", "right")
						:attr('data-sort-value', v)
					:done()
					:tag( 'td' )
						:wikitext( w==0 and "0%" or string.format("%.2f%%", 100*w ) )
						:css("text-align", "right")
						:attr('data-sort-value', w)
					:done()
					:tag( 'td' )
						:wikitext( s==0 and "0%" or string.format("%.2f%%", 100*s ) )
						:css("text-align", "right")
						:attr('data-sort-value', s)
					:done()
				:done()
			end
		end
	end

	resultsDiv:node(tostring(resultsTable))
	return resultsDiv
end

return p