Module:Shop calculator

From RuneRealm Wiki
Jump to navigation Jump to search

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

local p = {}

local paramTest = require('Module:Paramtest')
local yesNo = require('Module:Yesno')

function truncate(num)
	local whole, decimal = math.modf(num + 0.000001) -- addition is to prevent floating point rounding issues
	return whole
end

function sell(basePrice, shopBuysAt, delta, baseStock, currentStock, quantitySold, itemValue)
	local total = 0
	
	local upperBound = truncate(itemValue + (shopBuysAt * itemValue)) -- Item value + base price shop buys at
	local lowerBound = truncate(itemValue * .1)
	
	local function understockSellPrice(stockDelta)
		return truncate(itemValue * (shopBuysAt + (delta * stockDelta)))
	end
	
	local function overstockSellPrice(stockDelta)
		return truncate(itemValue * (shopBuysAt - (delta * stockDelta)))
	end
	
	local function applyBounds(num)
		if(num > upperBound) then
			return upperbound
		elseif(num <= lowerBound) then
			return lowerBound
		else
			return num
		end
	end
	
	for i = quantitySold, 1, -1 do
		local profit = 0
		if(currentStock < baseStock) then
			profit = applyBounds(understockSellPrice(baseStock - currentStock))
		elseif(currentStock == baseStock) then
			profit = applyBounds(basePrice)
		elseif(currentStock > baseStock) then
			profit = applyBounds(overstockSellPrice(currentStock - baseStock))
		end
		total = total + profit
		currentStock = currentStock + 1
	end
	
	return total, ''
end

function buy(basePrice, shopSellsAt, delta, baseStock, currentStock, quantityBought, itemValue)
	local total = 0
	local warningString = ''
	
	local upperBound = truncate(itemValue * (shopSellsAt + 5)) -- +500% base price
	local lowerBound = truncate(itemValue * (shopSellsAt - 1)) -- -100% base price
	local lowererBound = truncate(itemValue * .1)
	local minimumBound = 1
	
	if(currentStock == 0) then
		return 0, 'You cannot purchase from 0 stock.'
	end
	
	if(quantityBought > currentStock) then
		quantityBought = currentStock
		warningString = 'You can only purchase ' .. currentStock .. ' items. Purchasing ' .. quantityBought .. ' items instead.'
	end
	
	local function overstockBuyPrice(stockDelta)
		return truncate(itemValue / (stockDelta * delta + shopSellsAt))
	end
	
	local function understockBuyPrice(stockDelta)
		return truncate(itemValue * (stockDelta * delta + shopSellsAt))
	end
	
	local function applyBounds(num)
		if(num > upperBound) then
			return upperBound
		elseif(num < minimumBound) then
			return minimumBound
		elseif(num < lowererBound) then
			return lowererBound
		elseif(num < lowerBound) then
			return lowerBound
		else
			return num
		end
	end
	
	for i = quantityBought, 1, -1 do
		local cost = 0
		if(currentStock > baseStock) then
			cost = applyBounds(overstockBuyPrice(currentStock - baseStock))
		elseif(currentStock == baseStock) then
			cost = applyBounds(basePrice)
		elseif(currentStock < baseStock) then
			cost = applyBounds(understockBuyPrice(baseStock - currentStock))
		end
		total = total + cost
		currentStock = currentStock - 1
	end
	
	return total, warningString
end

function p._main(args)
	local buying = (args.action == 'Buying')
	local basePrice = buying and paramTest.default_to(tonumber(args.priceShopSellsAt), 1) or paramTest.default_to(tonumber(args.priceShopBuysAt), 0)
	local exchangeAt = buying and paramTest.default_to(tonumber(args.shopSellsAtValue), 1) or paramTest.default_to(tonumber(args.shopBuysAtValue), 0)
	local delta = paramTest.default_to(tonumber(args.delta), 0)
	local baseStock = paramTest.default_to(tonumber(args.baseStock), 1)
	local currentStock = paramTest.default_to(tonumber(args.currentStock), 1)
	local quantityExchanged = buying and paramTest.default_to(tonumber(args.buyQuantity), 1) or paramTest.default_to(tonumber(args.sellQuantity), 1)

	exchangeAt = exchangeAt / 100
	delta = delta / 100
	
	local itemValue = truncate(basePrice / exchangeAt)

	local totalCoins = 0
	local warning = ''
	
	if(buying) then
		totalCoins, warning = buy(basePrice, exchangeAt, delta, baseStock, currentStock, quantityExchanged, itemValue)
	else -- selling
		totalCoins, warning = sell(basePrice, exchangeAt, delta, baseStock, currentStock, quantityExchanged, itemValue)
	end

	return warning .. '\n' .. tostring(totalCoins)
end

--[[ DEBUG example: Lowes Sells at: 100.0% • Buys at: 55.0% • Change per: 1.0% Stock: 600 Sold at: 80 Bought at: 44
p._main({ action = 'Buying', priceShopSellsAt = 80, shopSellsAtValue = 100, delta = 1, baseStock = 600, currentStock = 601, buyQuantity = 50 }) -- result 4920
p._main({ action = 'Buying', priceShopSellsAt = 50, shopSellsAtValue = 100, delta = 3, baseStock = 10, currentStock = 5, buyQuantity = 1 }) -- result 57
p._main({ action = 'Selling', priceShopBuysAt = 80, shopBuysAtValue = 100, delta = 1, baseStock = 600, currentStock = 600, sellQuantity = 50 }) -- result should be 3000
p._main({ action = 'Selling', priceShopBuysAt = 44, shopBuysAtValue = 55, delta = 1, baseStock = 600, currentStock = 600, sellQuantity = 50 }) -- result is 1210
p._main({ action = 'Selling', priceShopBuysAt = 36, shopBuysAtValue = 60, delta = 2, baseStock = 0, currentStock = 300, sellQuantity = 1 }) -- result is 6
--]]

function p.main(frame)
	local args = frame.args
	--mw.logObject(args)
	return p._main(args)
end

return p