Module:SCValue: Difference between revisions
From Melvor Idle
No edit summary |
(Amend for 1.3 currency changes) |
||
(2 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') | ||
Line 7: | Line 8: | ||
local Number = require('Module:Number') | local Number = require('Module:Number') | ||
local Icons = require('Module:Icons') | local Icons = require('Module:Icons') | ||
local function getPurchase(itemName) | local function getPurchase(itemName) | ||
local func = | local func = | ||
function(purchase, name) | function(purchase, name) | ||
return name == itemName | return name == itemName | ||
Line 21: | Line 21: | ||
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 | local currVal = 0 | ||
if items ~= nil then | if items ~= nil then | ||
for _, item in | 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 | ||
end | end | ||
return | return currVal | ||
end | end | ||
-- Get total costs (including gp/item costs) | -- Get total costs (including gp/item costs) | ||
local | local currCost = 0 | ||
if costs. | 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 | -- Get gross profit from sale | ||
local | local currProfit = getItemValues(sales.items) | ||
-- Calculate actual profit | -- Calculate actual profit | ||
return | return currProfit - currCost | ||
end | end | ||
local function getSellablePurchases(checkFunc) | |||
local function getSellablePurchases() | 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 | ||
if items == nil or Shared.tableIsEmpty(items) then | |||
return false | |||
end | |||
if checkFunc == nil then | |||
return true | |||
end | |||
return checkFunc(purchase) | |||
end | end | ||
return Shop.getCategoryPurchases(func, 'Slayer') | return Shop.getCategoryPurchases(func, 'Slayer') | ||
end | end | ||
local function getMostProfitablePurchases(amount) | local function getMostProfitablePurchases(amount, gainedCurrencyID, spentCurrencyID, includeOnlyBulk) | ||
amount = tonumber(amount) | 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 = {} | local data = {} | ||
-- Gather value data about | -- Gather value data about Shop Items | ||
for _, v in | for _, v in ipairs(getSellablePurchases(func)) do | ||
local | local gainedValue = getPurchaseValue(v, gainedCurrencyID) | ||
local | local spentValue = 0 | ||
local | 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, { | table.insert(data, { | ||
Purchase = v, | Purchase = v, | ||
spentValue = spentValue, | |||
gainedValue = gainedValue, | |||
gainedPerSpent = gainedPerSpent, | |||
}) | }) | ||
end | end | ||
-- Sort by most profitable to least profitable | -- Sort by most profitable to least profitable | ||
table.sort(data, function(a, b) return a. | table.sort(data, function(a, b) return a.gainedPerSpent > b.gainedPerSpent end) | ||
-- Keep top x most profitable entries only | -- Keep top x most profitable entries only | ||
Line 93: | Line 122: | ||
return entries | return entries | ||
end | end | ||
return data | return data | ||
end | end | ||
function p.getSCItemProfits(frame) | function p.getSCItemProfits(frame) | ||
local args = frame:getParent().args | |||
return p._getCurrencyItemProfits(args[1], 'melvorD:GP', 'melvorD:SlayerCoins', args[2] or true) | |||
end | end | ||
function p. | function p._getCurrencyItemProfits(amount, gainedCurrencyID, spentCurrencyID, includeOnlyBulk) | ||
local purchases = getMostProfitablePurchases(amount) | 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') | local html = mw.html.create('table') | ||
:addClass('wikitable sortable stickyHeader') | :addClass('wikitable sortable stickyHeader') | ||
html:tag('tr') | html:tag('tr') | ||
:tag('th'):attr('colspan', 2) | :tag('th'):attr('colspan', 2) | ||
Line 111: | Line 159: | ||
:tag('th'):wikitext('Cost') | :tag('th'):wikitext('Cost') | ||
:tag('th'):wikitext('Requirements') | :tag('th'):wikitext('Requirements') | ||
:tag('th'):wikitext(' | :tag('th'):wikitext(gainedName .. ' Value') | ||
:tag('th'):wikitext(' | :tag('th'):wikitext(gainedName .. ' per ' .. spentName) | ||
for _, v in | for _, v in ipairs(purchases) do | ||
local purchase = v.Purchase | local purchase = v.Purchase | ||
local name = Common.getPurchaseName(purchase) | local name = Common.getPurchaseName(purchase) | ||
local expansionIcon = Shop._getPurchaseExpansionIcon(purchase) | local expansionIcon = Shop._getPurchaseExpansionIcon(purchase) | ||
local costs = Shop.getCostString(purchase.cost, false) | local costs = Shop.getCostString(purchase.cost, false) | ||
html:tag('tr') | html:tag('tr') | ||
:tag('td'):addClass('table-img') | :tag('td'):addClass('table-img') | ||
Line 126: | Line 174: | ||
:wikitext(expansionIcon) | :wikitext(expansionIcon) | ||
:wikitext(Common.getPurchaseIcon({purchase, noicon=true})) | :wikitext(Common.getPurchaseIcon({purchase, noicon=true})) | ||
:tag('td'):attr('data-sort-value', v. | :tag('td'):attr('data-sort-value', v.spentValue) | ||
:css('text-align', 'right') | :css('text-align', 'right') | ||
:wikitext(costs) | :wikitext(costs) | ||
:tag('td'):wikitext(Common.getRequirementString(purchase.purchaseRequirements, 'None')) | :tag('td'):wikitext(Common.getRequirementString(purchase.purchaseRequirements, 'None')) | ||
:tag('td'):attr('data-sort-value', v. | :tag('td'):attr('data-sort-value', v.gainedValue) | ||
:css('text-align', 'right') | :css('text-align', 'right') | ||
:wikitext(Icons. | :wikitext(Icons._Currency(gainedCurrencyID, v.gainedValue)) | ||
:tag('td'):attr('data-sort-value', v. | :tag('td'):attr('data-sort-value', v.gainedPerSpent) | ||
:css('text-align', 'right') | :css('text-align', 'right') | ||
:wikitext(Icons. | :wikitext(Icons._Currency(gainedCurrencyID, Number.autoround(v.gainedPerSpent))) | ||
end | end | ||
return tostring(html) | return tostring(html) | ||
end | end | ||
function p.getSCValue( | function p.getSCValue(frame) | ||
local purchase = getPurchase( | 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 | if purchase == nil then | ||
return Shared.printError("No Slayer Shop item exists with the name: " .. | return Shared.printError("No Slayer Shop item exists with the name: " .. itemName) | ||
end | end | ||
return | 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() | ||
mw.logObject(getPurchase("Magical Ring")) | |||
end | end | ||
return p | return p |
Latest revision as of 00:58, 20 June 2024
This module can be used to get information regarding 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