17,105
edits
No edit summary |
(Amend for 1.3 currency changes) |
||
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 9: | Line 10: | ||
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 20: | 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(checkFunc) | ||
local func = | local func = | ||
function(purchase, name) | function(purchase, name) | ||
-- Exclude SC Purchases that provide no items. | -- Exclude SC Purchases that provide no items. | ||
Line 61: | Line 70: | ||
return true | return true | ||
end | end | ||
return checkFunc(purchase) | return checkFunc(purchase) | ||
end | end | ||
return Shop.getCategoryPurchases(func, 'Slayer') | return Shop.getCategoryPurchases(func, 'Slayer') | ||
end | end | ||
local function getMostProfitablePurchases(amount, includeOnlyBulk) | local function getMostProfitablePurchases(amount, gainedCurrencyID, spentCurrencyID, includeOnlyBulk) | ||
amount = tonumber(amount) | amount = tonumber(amount) | ||
if includeOnlyBulk == nil then includeOnlyBulk = true end | if includeOnlyBulk == nil then includeOnlyBulk = true end | ||
local func = function(x) | local func = function(x) | ||
if includeOnlyBulk == true then | if includeOnlyBulk == true then | ||
return x.allowQuantityPurchase == true | return x.allowQuantityPurchase == true | ||
else | else | ||
return true | return true | ||
end | end | ||
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 103: | Line 122: | ||
return entries | return entries | ||
end | end | ||
return data | return data | ||
end | end | ||
Line 109: | Line 128: | ||
function p.getSCItemProfits(frame) | function p.getSCItemProfits(frame) | ||
local args = frame:getParent().args | local args = frame:getParent().args | ||
return p. | 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, 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') | 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 123: | 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 138: | 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 | ||
Line 155: | Line 191: | ||
function p.getSCValue(frame) | function p.getSCValue(frame) | ||
local args = frame:getParent().args | local args = frame:getParent().args | ||
return p._getItemSellsFor(args[1], args[2], args.round) | return p._getItemSellsFor(args[1], 'melvorD:SlayerCoins', args[2], args.round) | ||
end | end | ||
function p. | function p._getItemCurrencyValue(itemName, currencyID, multiplier, rounding) | ||
local purchase = getPurchase(itemName) | local purchase = getPurchase(itemName) | ||
if purchase == nil then | if purchase == nil then | ||
return Shared.printError("No Slayer Shop item exists with the name: " .. itemName) | return Shared.printError("No Slayer Shop item exists with the name: " .. itemName) | ||
end | end | ||
local itemValue = getPurchaseValue(purchase) | local itemValue = getPurchaseValue(purchase, currencyID) | ||
multiplier = tonumber(multiplier) or 1 | multiplier = tonumber(multiplier) or 1 | ||
rounding = tonumber(rounding) or 0 | rounding = tonumber(rounding) or 0 | ||
return Number.round2(itemValue * multiplier, rounding) | return Number.round2(itemValue * multiplier, rounding) | ||
end | end |