Module:SCValue: Difference between revisions

From Melvor Idle
No edit summary
No edit summary
 
(One intermediate revision by the same user not shown)
Line 7: Line 7:
local Number = require('Module:Number')
local Number = require('Module:Number')
local Icons = require('Module:Icons')
local Icons = require('Module:Icons')
local Debug = require('Module:Debug')


local function getPurchase(itemName)
local function getPurchase(itemName)
Line 50: Line 49:
end
end


-- Returns all SC items that can be sold for GP, and can be bought in bulk.
local function getSellablePurchases(checkFunc)
local function getSellablePurchases()
-- We need something to sell!
-- We also want to buy/sell massive quantities for profit!
local func =  
local func =  
function(purchase, name)
function(purchase, name)
-- Exclude SC Purchases that provide no items.
local items = purchase.contains.items
local items = purchase.contains.items
return purchase.allowQuantityPurchase and
if items == nil or Shared.tableIsEmpty(items) then
items ~= nil and
return false
not Shared.tableIsEmpty(items)
end
 
if checkFunc == nil then
return true
end
return checkFunc(purchase)
end
end
Line 65: Line 68:
end
end


local function getMostProfitablePurchases(amount)
local function getMostProfitablePurchases(amount, includeOnlyBulk)
amount = tonumber(amount)
amount = tonumber(amount)
amount = math.max(amount, 1)
if includeOnlyBulk == nil then includeOnlyBulk = true end
local func = function(x)
if includeOnlyBulk == true then
return x.allowQuantityPurchase == true
else
return true
end
end
local data = {}
local data = {}
-- Gather value data about SC Shop Items
-- Gather value data about SC Shop Items
for _, v in pairs(getSellablePurchases()) do
for _, v in pairs(getSellablePurchases(func)) do
local gpValue = getPurchaseValue(v)
local gpValue = getPurchaseValue(v)
local scCost = (v.cost.slayerCoins or {}).cost or 0
local scCost = (v.cost.slayerCoins or {}).cost or 0
Line 98: Line 108:


function p.getSCItemProfits(frame)
function p.getSCItemProfits(frame)
local args = frame:getParent().args
return p._getSCItemProfits(args[1], args[2] or true)
end
end


function p._getSCItemProfits(amount)
function p._getSCItemProfits(amount, includeOnlyBulk)
local purchases = getMostProfitablePurchases(amount)
local purchases = getMostProfitablePurchases(amount, includeOnlyBulk)


local html = mw.html.create('table')
local html = mw.html.create('table')
Line 141: Line 153:
end
end


function p.getSCValue(item)
function p.getSCValue(frame)
local purchase = getPurchase(item)
local args = frame:getParent().args
return p._getItemSellsFor(args[1], args[2], args.round)
end
 
function p._getSCValue(itemName, multiplier, rounding)
local purchase = getPurchase(itemName)
if purchase == nil then
if purchase == nil then
return Shared.printError("No Slayer Shop item exists with the name: " .. item)
return Shared.printError("No Slayer Shop item exists with the name: " .. itemName)
end
end
return getPurchaseValue(purchase)
local itemValue = getPurchaseValue(purchase)
multiplier = tonumber(multiplier) or 1
rounding = tonumber(rounding) or 0
return Number.round2(itemValue * multiplier, rounding)
end
end


function p.test()
function p.test()
return p._getSCItemProfits(1)
mw.logObject(getPurchase("Magical Ring"))
 
--mw.log(p.getSCValue(item))
end
end
return p
return p

Latest revision as of 19:37, 6 May 2024

This module can be used to get information regarding SC Slayer Coins related shop purchases. For instance, it calculates for much effective profit there can be gained or lost by buying specific items with SC and selling them for GP.


local p = {}

local Shared = require('Module:Shared')
local Shop = require('Module:Shop')
local Items = require('Module:Items')
local Common = require('Module:Common')
local Number = require('Module:Number')
local Icons = require('Module:Icons')

local function getPurchase(itemName)
	local func = 
		function(purchase, name)
			return name == itemName
		end

	local purchList = Shop.getCategoryPurchases(func, 'Slayer')
	if purchList ~= nil and not Shared.tableIsEmpty(purchList) then
		return purchList[1]
	end
end

local function getPurchaseValue(purchase)
	if purchase == nil or purchase.cost == nil or purchase.contains == nil 
	then return 0 end
	
	local costs = purchase.cost
	local sales = purchase.contains
	
	local function getItemValues(items)
		local gpVal = 0
		if items ~= nil then
			for _, item in pairs(items) do
				gpVal = gpVal + Items.getItemValueByID(item['id']) * item['quantity']
			end
		end	
		return gpVal
	end
	
	-- Get total costs (including gp/item costs)
	local gpCost = 0
	if costs.gp ~= nil then	gpCost = costs.gp['cost'] or 0 end
	gpCost = gpCost + getItemValues(costs.items)

	-- Get gross profit from sale
	local gpProfit = getItemValues(sales.items)

	-- Calculate actual profit
	return gpProfit - gpCost
end

local function getSellablePurchases(checkFunc)
	local func = 
		function(purchase, name)
			-- Exclude SC Purchases that provide no items.
			local items = purchase.contains.items
			if items == nil or Shared.tableIsEmpty(items) then
				return false
			end

			if checkFunc == nil then
				return true
			end
			
			return checkFunc(purchase)
		end
		
	return Shop.getCategoryPurchases(func, 'Slayer')
end

local function getMostProfitablePurchases(amount, includeOnlyBulk)
	amount = tonumber(amount)
	if includeOnlyBulk == nil then includeOnlyBulk = true end
	
	local func = function(x)
			if includeOnlyBulk == true then 
				return x.allowQuantityPurchase == true 
			else
				return true 
			end
		end
	local data = {}
	-- Gather value data about SC Shop Items
	for _, v in pairs(getSellablePurchases(func)) do
		local gpValue = getPurchaseValue(v)
		local scCost = (v.cost.slayerCoins or {}).cost or 0
		local gpPersc = (scCost ~= 0) and (gpValue / scCost) or (gpValue == 0 and 0 or 0)
		
		table.insert(data, {
			Purchase = v,
			SCCost = scCost,
			GPValue = gpValue,
			GPPerSC = gpPersc,
		})
	end
	
	-- Sort by most profitable to least profitable
	table.sort(data, function(a, b) return a.GPPerSC > b.GPPerSC end)

	-- Keep top x most profitable entries only
	if amount ~= nil then
		local entries = {}
		for i = 1, math.min(#data, amount) do table.insert(entries, data[i]) end
		return entries
	end
	
	return data
end

function p.getSCItemProfits(frame)
	local args = frame:getParent().args
	return p._getSCItemProfits(args[1], args[2] or true)
end

function p._getSCItemProfits(amount, includeOnlyBulk)
	local purchases = getMostProfitablePurchases(amount, includeOnlyBulk)

	local html = mw.html.create('table')
		:addClass('wikitable sortable stickyHeader')
	
	html:tag('tr')
			:tag('th'):attr('colspan', 2)
					  :wikitext('Purchase')
			:tag('th'):wikitext('Cost')
			:tag('th'):wikitext('Requirements')
			:tag('th'):wikitext('GP Value')
			:tag('th'):wikitext('GP per SC')
			
	for _, v in pairs(purchases) do
		local purchase =  v.Purchase
		local name = Common.getPurchaseName(purchase)
		local expansionIcon = Shop._getPurchaseExpansionIcon(purchase)
		local costs = Shop.getCostString(purchase.cost, false)
		
		html:tag('tr')
				:tag('td'):addClass('table-img')
						  :wikitext(Common.getPurchaseIcon({purchase, notext=true, size='50'}))
				:tag('td'):attr('data-sort-value', name)
						  :wikitext(expansionIcon)
						  :wikitext(Common.getPurchaseIcon({purchase, noicon=true}))
				:tag('td'):attr('data-sort-value', v.SCCost)
						  :css('text-align', 'right')
						  :wikitext(costs)
				:tag('td'):wikitext(Common.getRequirementString(purchase.purchaseRequirements, 'None'))
				:tag('td'):attr('data-sort-value', v.GPValue)
						  :css('text-align', 'right')
						  :wikitext(Icons.GP(v.GPValue))
				:tag('td'):attr('data-sort-value', v.GPPerSC)
						  :css('text-align', 'right')
						  :wikitext(Icons.GP(Number.autoround(v.GPPerSC)))
	end
	
	return tostring(html)
end

function p.getSCValue(frame)
	local args = frame:getParent().args
	return p._getItemSellsFor(args[1], args[2], args.round)
end

function p._getSCValue(itemName, multiplier, rounding)
	local purchase = getPurchase(itemName)
	if purchase == nil then
		return Shared.printError("No Slayer Shop item exists with the name: " .. itemName)
	end
	
	local itemValue = getPurchaseValue(purchase)
	multiplier = tonumber(multiplier) or 1
	rounding = tonumber(rounding) or 0
	
	return Number.round2(itemValue * multiplier, rounding)
end

function p.test()
	mw.logObject(getPurchase("Magical Ring"))
end
return p