Module:SCValue: Difference between revisions

From Melvor Idle
(Created page with "local p = {} local Shared = require('Module:Shared') local Shop = require('Module:Shop') local Items = require('Module:Items') --local Debug = require('Module:Debug') local function getPurchase(itemName) return Shop.getPurchase(itemName) 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...")
 
(Amend for 1.3 currency changes)
 
(5 intermediate revisions by one other user not shown)
Line 2: Line 2:


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


local function getPurchase(itemName)
local function getPurchase(itemName)
return Shop.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
end


local function getPurchaseValue(purchase)
local function getPurchaseValue(purchase, currencyID)
if purchase == nil or purchase.cost == nil or purchase.contains == nil  
if purchase == nil or purchase.cost == nil or purchase.contains == nil
then return 0 end
then return 0 end
 
local costs = purchase.cost
local costs = purchase.cost
local sales = purchase.contains
local sales = purchase.contains
 
local function getItemValues(items)
local function getItemValues(items)
local gpVal = 0
local currVal = 0
if items ~= nil then
if items ~= nil then
for _, v in pairs(items) do
for _, item in ipairs(items) do
gpVal = gpVal + Items.getItemValueByID(v['id']) * v['quantity']
local itemObj = Items.getItemByID(item.id)
local itemCurrencyID = itemObj.sellsForCurrency or 'melvorD:GP'
if itemCurrencyID == currencyID then
currVal = currVal + (itemObj.sellsFor or 0) * item.quantity
end
end
end
end
end
return gpVal
return currVal
end
end
 
-- Get total costs (including gp/item costs)
-- Get total costs (including gp/item costs)
local gpCost = 0
local currCost = 0
if costs.gp ~= nil then gpCost = costs.gp['cost'] or 0 end
if costs ~= nil and costs.currencies ~= nil then
gpCost = gpCost + getItemValues(costs.items)
local purchCurrCost = GameData.getEntityByProperty(costs.currencies, 'currency', currencyID)
if purchCurrCost ~= nil then
currCost = currCost + (purchCurrCost.cost or 0)
end
end


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


-- Calculate actual profit
-- Calculate actual profit
return gpProfit - gpCost
return currProfit - currCost
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, gainedCurrencyID, spentCurrencyID, 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 Shop Items
for _, v in ipairs(getSellablePurchases(func)) do
local gainedValue = getPurchaseValue(v, gainedCurrencyID)
local spentValue = 0
if v.cost ~= nil and v.cost.currencies ~= nil then
local spentCurrencyCost = GameData.getEntityByProperty(v.cost.currencies, 'currency', spentCurrencyID)
if spentCurrencyCost ~= nil then
spentValue = spentCurrencyCost.cost or 0
end
end
 
local gainedPerSpent = 0
if gainedValue ~= 0 and spentValue ~= 0 then
gainedPerSpent = gainedValue / spentValue
end
 
table.insert(data, {
Purchase = v,
spentValue = spentValue,
gainedValue = gainedValue,
gainedPerSpent = gainedPerSpent,
})
end
 
-- Sort by most profitable to least profitable
table.sort(data, function(a, b) return a.gainedPerSpent > b.gainedPerSpent 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._getCurrencyItemProfits(args[1], 'melvorD:GP', 'melvorD:SlayerCoins', args[2] or true)
end
 
function p._getCurrencyItemProfits(amount, gainedCurrencyID, spentCurrencyID, includeOnlyBulk)
local currencyShortNames = {
["melvorD:GP"] = 'GP',
["melvorD:SlayerCoins"] = 'SC',
["melvorD:RaidCoins"] = 'RC',
["melvorItA:AbyssalPieces"] = 'AP',
["melvorItA:AbyssalSlayerCoins"] = 'ASC'
}
local gainedName, spentName = currencyShortNames[gainedCurrencyID], currencyShortNames[spentCurrencyID]
 
if gainedName == nil or spentName == nil then
local unknownID = (
(gainedName == nil and (gainedCurrencyID or 'GainedCurrency'))
or (spentCurrencyID or 'SpentCurrency')
)
return Shared.printError('Unknown currency ID: ' .. unknownID)
end
 
local purchases = getMostProfitablePurchases(amount, gainedCurrencyID, spentCurrencyID, 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(gainedName .. ' Value')
:tag('th'):wikitext(gainedName .. ' per ' .. spentName)
 
for _, v in ipairs(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.spentValue)
  :css('text-align', 'right')
  :wikitext(costs)
:tag('td'):wikitext(Common.getRequirementString(purchase.purchaseRequirements, 'None'))
:tag('td'):attr('data-sort-value', v.gainedValue)
  :css('text-align', 'right')
  :wikitext(Icons._Currency(gainedCurrencyID, v.gainedValue))
:tag('td'):attr('data-sort-value', v.gainedPerSpent)
  :css('text-align', 'right')
  :wikitext(Icons._Currency(gainedCurrencyID, Number.autoround(v.gainedPerSpent)))
end
 
return tostring(html)
end
end


function p.getSCValue(item)
function p.getSCValue(frame)
local purchase = getPurchase(item)
local args = frame:getParent().args
return getPurchaseValue(purchase)
return p._getItemSellsFor(args[1], 'melvorD:SlayerCoins', args[2], args.round)
end
 
function p._getItemCurrencyValue(itemName, currencyID, 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, currencyID)
multiplier = tonumber(multiplier) or 1
rounding = tonumber(rounding) or 0
 
return Number.round2(itemValue * multiplier, rounding)
end
end


function p.test()
function p.test()
local item = 'Necromancer Hat'
mw.logObject(getPurchase("Magical Ring"))
local s = getPurchase(item)
mw.log(getPurchaseValue(s))
end
end
return p
return p

Latest revision as of 00:58, 20 June 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 GameData = require('Module:GameData')
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, currencyID)
	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 currVal = 0
		if items ~= nil then
			for _, item in ipairs(items) do
				local itemObj = Items.getItemByID(item.id)
				local itemCurrencyID = itemObj.sellsForCurrency or 'melvorD:GP'
				if itemCurrencyID == currencyID then
					currVal = currVal + (itemObj.sellsFor or 0) * item.quantity
				end
			end
		end
		return currVal
	end

	-- Get total costs (including gp/item costs)
	local currCost = 0
	if costs ~= nil and costs.currencies ~= nil then
		local purchCurrCost = GameData.getEntityByProperty(costs.currencies, 'currency', currencyID)
		if purchCurrCost ~= nil then
			currCost = currCost + (purchCurrCost.cost or 0)
		end
	end

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

	-- Calculate actual profit
	return currProfit - currCost
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, gainedCurrencyID, spentCurrencyID, 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 Shop Items
	for _, v in ipairs(getSellablePurchases(func)) do
		local gainedValue = getPurchaseValue(v, gainedCurrencyID)
		local spentValue = 0
		if v.cost ~= nil and v.cost.currencies ~= nil then
			local spentCurrencyCost = GameData.getEntityByProperty(v.cost.currencies, 'currency', spentCurrencyID)
			if spentCurrencyCost ~= nil then
				spentValue = spentCurrencyCost.cost or 0
			end
		end

		local gainedPerSpent = 0
		if gainedValue ~= 0 and spentValue ~= 0 then
			gainedPerSpent = gainedValue / spentValue
		end

		table.insert(data, {
			Purchase = v,
			spentValue = spentValue,
			gainedValue = gainedValue,
			gainedPerSpent = gainedPerSpent,
		})
	end

	-- Sort by most profitable to least profitable
	table.sort(data, function(a, b) return a.gainedPerSpent > b.gainedPerSpent 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._getCurrencyItemProfits(args[1], 'melvorD:GP', 'melvorD:SlayerCoins', args[2] or true)
end

function p._getCurrencyItemProfits(amount, gainedCurrencyID, spentCurrencyID, includeOnlyBulk)
	local currencyShortNames = {
		["melvorD:GP"] = 'GP',
		["melvorD:SlayerCoins"] = 'SC',
		["melvorD:RaidCoins"] = 'RC',
		["melvorItA:AbyssalPieces"] = 'AP',
		["melvorItA:AbyssalSlayerCoins"] = 'ASC'
	}
	local gainedName, spentName = currencyShortNames[gainedCurrencyID], currencyShortNames[spentCurrencyID]

	if gainedName == nil or spentName == nil then
		local unknownID = (
			(gainedName == nil and (gainedCurrencyID or 'GainedCurrency'))
			or (spentCurrencyID or 'SpentCurrency')
		)
		return Shared.printError('Unknown currency ID: ' .. unknownID)
	end

	local purchases = getMostProfitablePurchases(amount, gainedCurrencyID, spentCurrencyID, 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(gainedName .. ' Value')
			:tag('th'):wikitext(gainedName .. ' per ' .. spentName)

	for _, v in ipairs(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.spentValue)
						  :css('text-align', 'right')
						  :wikitext(costs)
				:tag('td'):wikitext(Common.getRequirementString(purchase.purchaseRequirements, 'None'))
				:tag('td'):attr('data-sort-value', v.gainedValue)
						  :css('text-align', 'right')
						  :wikitext(Icons._Currency(gainedCurrencyID, v.gainedValue))
				:tag('td'):attr('data-sort-value', v.gainedPerSpent)
						  :css('text-align', 'right')
						  :wikitext(Icons._Currency(gainedCurrencyID, Number.autoround(v.gainedPerSpent)))
	end

	return tostring(html)
end

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

function p._getItemCurrencyValue(itemName, currencyID, 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, currencyID)
	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